Blink Arrow рисует с UIBezierPath - PullRequest
0 голосов
/ 03 января 2019

У меня есть UIScrollView с длинным текстом.Я хочу проинформировать пользователей, что у него есть больше контента для чтения.Поэтому я добавил стрелку с UIBezierPath внизу.

class ArrowView: UIView {
    var arrowPath: UIBezierPath!
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
        self.drawArrow(from: CGPoint(x: rect.midX, y: rect.minY), to: CGPoint(x: rect.midX, y: rect.maxY),
                       tailWidth: 10, headWidth: 25, headLength: 20)

        //arrowPath.fill()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.backgroundColor = UIColor.darkGray
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    private func drawArrow(from start: CGPoint, to end: CGPoint, tailWidth: CGFloat, headWidth: CGFloat, headLength: CGFloat){
        let length = hypot(end.x - start.x, end.y - start.y)
        let tailLength = length - headLength

        func p(_ x: CGFloat, _ y: CGFloat) -> CGPoint { return CGPoint(x: x, y: y) }
        let points: [CGPoint] = [
            p(0, tailWidth / 2),
            p(tailLength, tailWidth / 2),
            p(tailLength, headWidth / 2),
            p(length, 0),
            p(tailLength, -headWidth / 2),
            p(tailLength, -tailWidth / 2),
            p(0, -tailWidth / 2)
        ]

        let cosine = (end.x - start.x) / length
        let sine = (end.y - start.y) / length
        let transform = CGAffineTransform(a: cosine, b: sine, c: -sine, d: cosine, tx: start.x, ty: start.y)

        let path = CGMutablePath()
        path.addLines(between: points, transform: transform)
        path.closeSubpath()

        arrowPath = UIBezierPath.init(cgPath: path)
    }
}

Мой вопрос: Как добиться анимации моргания на стрелке.Предположим, что он имеет градиентный слой от белого до синего.Он должен начинаться с белого до синего, затем синий должен быть виден в начальной точке, затем белый должен начинаться в конечной точке стрелки, и этот круг должен продолжаться.

В финале эта анимация должна информировать пользователей о том, что они могут прокрутить представление.

Как этого добиться?

enter image description here

Ответы [ 3 ]

0 голосов
/ 03 января 2019

Вы можете попробовать использовать CAGradientLayer вместе с CAAnimation.Добавьте градиент к вашему виду:

override func viewDidAppear(animated: Bool) {

    self.gradient = CAGradientLayer()
    self.gradient?.frame = self.view.bounds
    self.gradient?.colors = [ UIColor.white.cgColor, UIColor.white.cgColor]
    self.view.layer.insertSublayer(self.gradient, atIndex: 0)
    animateLayer()
}

func animateLayer(){

    var fromColors = self.gradient.colors
    var toColors: [AnyObject] = [UIColor.blue.cgColor,UIColor.blue.cgColor]
    self.gradient.colors = toColors
    var animation : CABasicAnimation = CABasicAnimation(keyPath: "colors")

    animation.fromValue = fromColors
    animation.toValue = toColors
    animation.duration = 3.00
    animation.isRemovedOnCompletion = true
    animation.fillMode = CAMediaTimingFillMode.forwards
    animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
    animation.delegate = self

    self.gradient?.addAnimation(animation, forKey:"animateGradient")
}

и продолжайте анимацию градиента в циклическом порядке, например:

override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
    self.toColors = self.fromColors;
    self.fromColors = self.gradient?.colors
    animateLayer()
}
0 голосов
/ 03 января 2019

Я решил это с помощью CABasicAnimation().Сначала добавьте градиентный слой в пользовательский UIView, затем примените к нему маску и добавьте анимацию.

override func draw(_ rect: CGRect) {
    // Drawing code
    self.drawArrow(from: CGPoint(x: rect.midX, y: rect.minY), to: CGPoint(x: rect.midX, y: rect.maxY),
                   tailWidth: 10, headWidth: 20, headLength: 15)

    //arrowPath.fill()

    let startColor = UIColor(red:0.87, green:0.87, blue:0.87, alpha:1.0).cgColor
    let finishColor = UIColor(red:0.54, green:0.54, blue:0.57, alpha:1.0).withAlphaComponent(0.5).cgColor

    let gradient = CAGradientLayer()
    gradient.frame = self.bounds
    gradient.colors = [startColor,finishColor]

    let shapeMask = CAShapeLayer()
    shapeMask.path = arrowPath.cgPath

    gradient.mask = shapeMask
    let animation = CABasicAnimation(keyPath: "colors")
    animation.fromValue = [startColor, finishColor]
    animation.toValue = [finishColor, startColor]
    animation.duration = 2.0
    animation.autoreverses = true
    animation.repeatCount = Float.infinity

    //add the animation to the gradient
    gradient.add(animation, forKey: nil)

    self.layer.addSublayer(gradient)

}
0 голосов
/ 03 января 2019

Вы можете поместить свою стрелку в объект UIView.Затем вы можете включить UIView в таймер, где он правильно сменит альфу.В зависимости от мигания или затухания, тем не менее, вы можете использовать анимации UIView для завершения желаемой анимации.

Я говорю uiview вместо использования scrollview, потому что вы не хотите скрывать scrollview.Таким образом, вы поместите его в представление, в котором находится только контейнер для безье-пути.

...