如何在 iOS 中为自定义属性设置动画 [英] How to animate a custom property in iOS

查看:26
本文介绍了如何在 iOS 中为自定义属性设置动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义 UIView,它使用 Core Graphics 调用绘制其内容.一切正常,但现在我想为影响显示的值变化设置动画.我有一个自定义属性可以在我的自定义 UView 中实现此目的:

I have a custom UIView that draws its contents using Core Graphics calls. All working well, but now I want to animate a change in value that affects the display. I have a custom property to achieve this in my custom UView:

var _anime: CGFloat = 0
var anime: CGFloat {
    set {
        _anime = newValue
        for(gauge) in gauges {
            gauge.animate(newValue)
        }
        setNeedsDisplay()
    }
    get {
        return _anime
    }
}

而且我已经从 ViewController 开始了一个动画:

And I have started an animation from the ViewController:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.emaxView.anime = 0.5
    UIView.animate(withDuration: 4) {
        DDLogDebug("in animations")
        self.emaxView.anime = 1.0
    }
}

这不起作用 - 动画值确实从 0.5 更改为 1.0,但它会立即更改.有两次对动画设置器的调用,一次值为 0.5,然后立即调用值为 1.0.如果我将我正在制作动画的属性更改为标准 UIView 属性,例如alpha,它工作正常.

This doesn't work - the animated value does change from 0.5 to 1.0 but it does so instantly. There are two calls to the anime setter, once with value 0.5 then immediately a call with 1.0. If I change the property I'm animating to a standard UIView property, e.g. alpha, it works correctly.

我来自 Android 背景,所以整个 iOS 动画框架对我来说看起来像是黑魔法.除了预定义的 UIView 属性之外,还有什么方法可以为属性设置动画?

I'm coming from an Android background, so this whole iOS animation framework looks suspiciously like black magic to me. Is there any way of animating a property other than predefined UIView properties?

下面是动画视图应该是什么样子 - 它大约每 1/2 秒获得一个新值,我希望指针在这段时间内从前一个值平滑移动到下一个值.更新它的代码是:

Below is what the animated view is supposed to look like - it gets a new value about every 1/2 second and I want the pointer to move smoothly over that time from the previous value to the next. The code to update it is:

open func animate(_ progress: CGFloat) {
    //DDLogDebug("in animate: progress \(progress)")
    if(dataValid) {
        currentValue = targetValue * progress + initialValue * (1 - progress)
    }
}

并在更新后调用 draw() 将使其使用新的指针位置重绘,在 initialValuetargetValue 之间插入

And calling draw() after it's updated will make it redraw with the new pointer position, interpolating between initialValue and targetValue

推荐答案

简短回答:使用 CADisplayLink 每 n 帧调用一次.示例代码:

Short answer: use CADisplayLink to get called every n frames. Sample code:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let displayLink = CADisplayLink(target: self, selector: #selector(animationDidUpdate))
    displayLink.preferredFramesPerSecond = 50
    displayLink.add(to: .main, forMode: .defaultRunLoopMode)
    updateValues()
}

var animationComplete = false
var lastUpdateTime = CACurrentMediaTime()
func updateValues() {
    self.emaxView.animate(0);
    lastUpdateTime = CACurrentMediaTime()
    animationComplete = false
}

func animationDidUpdate(displayLink: CADisplayLink) {

    if(!animationComplete) {
        let now = CACurrentMediaTime()
        let interval = (CACurrentMediaTime() - lastUpdateTime)/animationDuration
        self.emaxView.animate(min(CGFloat(interval), 1))
        animationComplete = interval >= 1.0
    }
}

}

代码可以改进和概括,但它正在做我需要的工作.

The code could be refined and generalised but it's doing the job I needed.

这篇关于如何在 iOS 中为自定义属性设置动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆