2016-12-02 1 views
1

Я сделал заказ кругового обзора прогресса на подклассы UIView, добавив CAShapeLayer подслой его слой и наиважнейшей drawRect() обновить path свойства формы слоя.CALayer с Animated Path содержанием, осматриваемыми/DESIGNABLE

Сделав вид @IBDesignable и progress@IBInspectable, я смог изменить его значение в Interface Builder и увидеть обновленный путь безье в реальном времени. Не важно, но действительно круто!

Далее я решил сделать анимированный путь: всякий раз, когда вы устанавливаете новое значение в коде, дуга, указывающая прогресс, должна «расти» от нулевой длины до любого процента круга (подумайте о дугах в Деятельности приложение в Apple Watch).

Для достижения этой цели, я сменил свою CAShapeLayer подслоя с помощью настраиваемой CALayer подкласса, который имеет свойство @dynamic (@NSManaged), наблюдаемый в качестве ключа для ananimation (я реализовал needsDisplayForKey(), actionForKey(), drawInContext() и т.д.).

Мой Посмотреть код (соответствующие части) выглядит примерно так:

// Triggers path update (animated) 
private var progress: CGFloat = 0.0 { 
    didSet { 
     updateArcLayer() 
    } 
} 

// Programmatic interface: 
// (pass false to achieve immediate change) 
func setValue(newValue: CGFloat, animated: Bool) { 
    if animated { 
     self.progress = newValue 
    } else { 
     arcLayer.animates = false 
     arcLayer.removeAllAnimations() 
     self.progress = newValue 
     arcLayer.animates = true 
    } 
} 

// Exposed to Interface Builder's inspector: 
@IBInspectable var currentValue: CGFloat { 
    set(newValue) { 
     setValue(newValue: currentValue, animated: false) 
     self.setNeedsLayout() 
    } 
    get { 
     return progress 
    } 
} 

private func updateArcLayer() { 
    arcLayer.frame = self.layer.bounds 
    arcLayer.progress = progress 
} 

И в слой код:

var animates: Bool = true 
@NSManaged var progress: CGFloat 

override class func needsDisplay(forKey key: String) -> Bool { 
    if key == "progress" { 
     return true 
    } 
    return super.needsDisplay(forKey: key) 
} 

override func action(forKey event: String) -> CAAction? { 
    if event == "progress" && animates == true { 
     return makeAnimation(forKey: event) 
    } 
    return super.action(forKey: event) 
} 

override func draw(in ctx: CGContext) { 
    ctx.beginPath() 

    // Define the arcs... 
    ctx.closePath() 
    ctx.setFillColor(fillColor.cgColor) 
    ctx.drawPath(using: CGPathDrawingMode.fill) 
} 

private func makeAnimation(forKey event: String) -> CABasicAnimation? { 
    let animation = CABasicAnimation(keyPath: event) 

    if let presentationLayer = self.presentation() { 
     animation.fromValue = presentationLayer.value(forKey: event) 
    } 

    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 
    animation.duration = animationDuration 
    return animation 
} 

анимационной работы, но теперь я могу» t получить мои пути для отображения в Interface Builder.

Я попытался реализации мой взгляд-х prepareForInterfaceBuilder() так:

override func prepareForInterfaceBuilder() { 
    super.prepareForInterfaceBuilder() 

    self.topLabel.text = "Hello, Interface Builder!" 
    updateArcLayer() 
} 

... и изменение текста этикетки отражается в Interface Builder, но путь не отображается.

Я что-то упустил?

ответ

1

Ну, не смешно ... Оказывается, заявление о моей @Inspectable собственности имела очень глупую ошибки.

Можете ли вы определить это?

@IBInspectable var currentValue: CGFloat { 
    set(newValue) { 
     setValue(newValue: currentValue, animated: false) 
     self.setNeedsLayout() 
    } 
    get { 
     return progress 
    } 
} 

Это должно быть:

@IBInspectable var currentValue: CGFloat { 
    set(newValue) { 
     setValue(newValue: newValue, animated: false) 
     self.setNeedsLayout() 
    } 
    get { 
     return progress 
    } 
} 

То есть, я отбрасывание переданного значения (newValue) и используя текущий (currentValue), чтобы установить внутренние переменную вместо этого. «Ведение журнала» значение (всегда 0.0) в Interface Builder (через свойство моего лейбла text!) Дал мне ключ.

Сейчас он работает нормально, нет необходимости в drawRect() и т.д.

+1

DrawRect() не является проклятием существования Core Animation в. Он должен быть изолирован от тех, кто использует Core Graphics и поражен из всех аспектов использования Core Animation. Отлично сработано! – Confused

Смежные вопросы