Почему мой CAShapeLayer неправильно анимируется с помощью UIView (с gif)?

введите здесь описание изображения

Итак, вот как это происходит.

Серая область — это UIView, замаскированный с помощью CAShapeLayer. Я добавил два UIBezierPath и использовал Even Odd Rule, чтобы удалить часть этой серой области. Вот почему он показывает линию, как если бы она демонстрировала полукруг слева.

Красный фон — это просто представление контейнера.

Теперь моя проблема в том, что когда я анимирую свой UIView, создается впечатление, что маска не обновляется правильно при анимации UIView.

Вот часть анимации UIView:

func didCompleteItem() {
    self.bar.plainProgressBarLeftAnchor?.constant = self.bar.bounds.width * (self.completedItemCount*self.barMeterMultiplier) / self.bar.bounds.width - self.bar.meterCornerRadius
    UIView.animate(withDuration: 1.0, delay: 0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
        self.bar.layoutIfNeeded()

    }, completion: nil)
}

Теперь, вот часть layoutSubviews, если вам нужно увидеть, как был создан CAShapeLayer.

override func layoutSubviews() {
    super.layoutSubviews()

    backgroundColor = GradientColor(.leftToRight, frame: self.bounds, colors: GradientFlatRed())
    layer.masksToBounds = true
    layer.cornerRadius = meterCornerRadius

    createMask()

}

var shapeLayer: CAShapeLayer = CAShapeLayer()
func createMask() {
    let bPath = UIBezierPath(roundedRect: plainProgressBar.bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width: 0, height: 0))
    let semiCircle = UIBezierPath(arcCenter: CGPoint(x: bounds.origin.x, y: plainProgressBar.bounds.origin.y+meterCornerRadius), radius: meterCornerRadius, startAngle: 3 * CGFloat.pi / 2, endAngle: CGFloat.pi / 2, clockwise: true)
    shapeLayer.frame = layer.bounds
    bPath.append(semiCircle)
    shapeLayer.path = bPath.cgPath
    shapeLayer.fillRule = kCAFillRuleEvenOdd
    plainProgressBar.layer.mask = shapeLayer
}

person rocky raccoon    schedule 09.11.2017    source источник
comment
Я бы нарисовал не только полукруг, но и полный круг, чтобы избежать проблемы. Кроме того, возможно, в layoutLayer() (эквивалент layoutSubView) это может помочь исправить.   -  person Larme    schedule 09.11.2017
comment
зачем layoutLayer() ее решать? Связано ли это с жизненным циклом представления?   -  person rocky raccoon    schedule 09.11.2017


Ответы (1)


Рисование растягиваемого круга и изменение ширины представления изображения, изображающего круг, даст вам эффект, который вам нужен, практически без усилий и без каких-либо артефактов, которые вы испытываете:

введите здесь описание изображения

person matt    schedule 09.11.2017
comment
Причина, по которой я уменьшаю серую область вместо создания растягивающегося красного круга, заключается в том, что мой красный фон является градиентным. Я мог бы использовать ваш подход и добавить градиент к кругу, но это не соответствовало бы моему выбору дизайна. Это все время будет выглядеть как градиентный круг, даже когда я его растяну, если вы понимаете, о чем я. Другими словами, я хочу, чтобы красный фон выглядел так, как будто он становится темно-красным. Вот почему сбой показывает более темный красный цвет с правой стороны. - person rocky raccoon; 09.11.2017
comment
Тогда я не думаю, что вы поставили вопрос очень ясно. Тем не менее, маскирование градиентом и изменение формы маски было очень хорошо реализовано в Stack Overflow. - person matt; 09.11.2017
comment
Тем не менее, я не думаю, что это существенно меняет мой ответ. Маска может быть представлением маски, представление маски может быть представлением изображения, и поэтому вы можете анимировать маску именно так, как я советую. - person matt; 09.11.2017
comment
Пересмотрел мой снимок экрана, чтобы показать, что анимация изображения-просмотра-как-маски работает именно так, как вы хотите. Просто настройте детали градиента, и вы дома. - person matt; 09.11.2017