美文网首页SwiftUI
使用Apple最新的Swift UI技术编写更好的app(6)

使用Apple最新的Swift UI技术编写更好的app(6)

作者: _我和你一样 | 来源:发表于2020-09-24 22:52 被阅读0次

    今天要说三个内容:Property Observers、@State、Animation

    1. Property Observers

    属性观察本质上就是看到变量发生变化时就执行一段代码。语法看起来和计算属性非常相似,但完全不相同

    var isFaceUp: Bool {
    willSet {
            if newValue {
                startUsingBonusTime()
            } else {
                stopUsingBonusTime()
            }
        }
    }
    

    在这里面,newValue 是个特殊的变量,是新值,是那个将要被设置或获取的值。还有一个didSet方法,里面有一个特殊变量是 oldValue,是旧值,是之前用的值。

    1. @State

    View 是 只读的。

    事实证明,所有的视图结构都完完全全是只读的。不管SwiftUI使用什么变量持有你的views都是let,因此除了初始化view时的变量外,使用var是没有意义的。也就是只有let或者只读的计算属性才有意义。

    为什么呢?

    有很多设计原因,比如可以可靠的处理变化高效的执行重绘,视图大多时候应该是无状态的,只需一直绘制它的model即可。他们不需要自己的状态,因此不需要设置成不是只读的。等等。

    那么,当view需要状态的时候呢?

    事实上在极少的情况下视图需要一些状态的。这样的变量总是临时的。所有的永久状态都应当属于model。

    比如说,你已进入“编辑模式”,并正在收集更改。 暂时显示了另一个视图以收集信息或通知用户。你希望动画开始,因此您需要设置动画的终点。

    你必须使用@State来标记这个临时状态,发生在@state var的变量变更会使view根据需要进行重绘。从这样意义上来说,它就像@ObservedObject

    当views需要state时@State var somethingTemporary: SomeType,实际上,这将为此在堆中腾出一些空间。
    这样做是因为View结构本身是只读的,还记得吗?并且当只读View重建时,新版本将继续指向它。 换句话说,对View的更改(通过其参数)不会转储该状态。很快,我们将了解这些@事物(例如@Published和@ObservedObject)是什么,但还不是。 现在,只知道您的View中的任何可读写var必须标有@State。
    谨慎使用它们。

    1. 动画

    什么可以动画?

    你只能对已经出现在屏幕上的容器中的视图的修改做动画。“Views in containers that are already on screen ”

    哪些修改呢?

    • View的出现和消失
    • 对视图的“可动画化”视图修改器的参数的更改
    • 对形状创建的参数的更改

    如何让动画动起来,有两种方式

    • 隐式动画:使用是私有view modifier 的 .animation(Animation)
    • 显示动画:将要修改的内容放在 withAnimation(Animation){}

    隐式动画:自动动画。所有的视图修改器(ViewModifier)参数总是动画的。这些改变是根据你指定的曲线和时间进行变化。简单的加上.animation(Animation)意思你要执行自动动画。

    Text(“👻 ”)
    .opacity(scary ? 1 : 0)
    .rotationEffect(Angle.degrees(upsideDown ? 180 : 0)) 
    .animation(Animation.easeInOut) // Swift可以推断出动画
    

    现在,不管什么时候发生变化, opacity/rotation 都会进行动画。由于对动画视图修改器的参数的更改具有动画效果,没有使用.animation()opacity/rotation 的变更会立刻从屏幕上显现。

    注意⚠️:.animation修饰符不适用于你想用在容器上的想法。 容器只是将.animation修饰符传播到它包含的所有视图里,换句话说,.animation不能像.padding那样工作,而更像.font。

    传递给.animation()的参数是一个 Animation 结构体。这个结构体可以让你控制动画,比如 持续时间, 延迟执行时间,重复,曲线等。

    动画曲线:是用来控制动画速率等,比如线性、淡入淡出、弹性等。

    隐式与显式动画
    这些“自动”隐式动画通常不是动画行为的主要来源。 它们通常用于“叶子”(即非容器)视图。
    或者,更一般而言,在通常独立于其他视图工作的视图上。
    回想一下,你不能为容器视图隐式设置动画(它会传播到内部的视图)。 那是因为在容器中,您开始希望能够协调View的动画。 本质上,包含在一起的一堆View希望一起进行动画处理。
    而且,它们可能都将响应某些用户操作或模型更改而一起进行动画处理。 这就是为什么要需要显示动画了。

    显式动画创建一个动画会话,在此期间...由于执行代码块而进行的所有合格更改将一起动画化。
    您提供要使用的动画(持续时间,曲线等)和代码块。

    withAnimation(.linear(duration: 2)) {
    // do something that will cause ViewModifier/Shape arguments to change somewhere 
    }
    

    显式动画几乎总是包裹在对ViewModel 意图函数里。 它们也包含在修改UI的地方比如进入编辑模式。 处理用户手势的代码不包裹在withAnimation中是很少见的。

    显式动画不会覆盖隐式动画。

    transitions过渡

    过度指定视图如何出现和离开。过度只不过是一对ViewModifiers。一个modifier是对移动视图之前的修改,另一个是移动视图之后的修改。因此,过渡实际上只是“更改视图修饰符的参数”动画的一种形式。非对称过渡具有2对ViewModifier。一对用于显示视图,另一对用于消失视图。示例:视图在显示时会淡入,但在消失时会在屏幕上飞过。

    当view出现和离开屏幕时如何指定ViewModifiers使用呢?使用.transition()。比如使用两个内置的过渡: .scale and .identity

    ZStack {
        if isFaceUp {
                RoundedRectangle() // default .transition is .opacity 
          Text(“👻 ”).transition(.scale)
        } else {
            RoundedRectangle(cornerRadius: 10).transition(.identity)
    } }
    

    如果 isFaceUp 变更了(当ZStack在屏幕上并且正在执行显式动画) 当变为false时,背面会立即出现,文字会缩小至没有,正面会淡出。当为true时,背面会立刻消失。文字会从无放大到有。

    不像.animation(), .transition()不会重新分配到容器的内容视图(但是Group和ForEach确实将.transition()分发到其内容视图)。.transition()仅指定ViewModifiers是什么。它不会导致任何动画的发生。换句话说,在这里将单词transition看作是名词,而不是动词。 您正在声明要使用的过渡,而不是导致过渡发生。

    过渡不适用于隐式动画,仅适用于显式动画。

    Shape和ViewModifier动画
    你现在可能已经注意到,所有实际的动画都发生在Shapes和ViewModifiers中。 那么他们如何参与动画呢?
    本质上,动画系统将动画持续时间分为几小段。
    Shape或ViewModifier可使动画系统知道需要分段的信息。 (例如,我们的“饼形”将要把饼的角度分成几部分。)
    动画系统然后告诉Shape / ViewModifier它应该显示的当前片段。 而且Shape / ViewModifier可以确保其代码始终能够反映出这一点。

    与动画系统的通信是通过两个变量(双向)进行的。 该变量是Animatable协议中的唯一内容。
    想要动画的Shape和ViewModifier必须实现此协议。
    var animatableData:Type
    类型必须实现协议VectorArithmetic。那是因为它必须能够在动画曲线上分解成小块。类型几乎总是浮点数(Float,Double,CGFloat)。但是还有另一个实现VectorArithmetic的结构称为AnimatablePair。 AnimatablePair将两个VectorArithmetics组合为一个VectorArithmetic!
    当然,您可以拥有AnimatablePairs的AnimatablePairs,因此你可以所有你想要的动画。

    由于animatableData双向通信,因此它是可读写的var。该变量的设置是动画系统,它告诉Shape / VM绘制哪一块。该变量的获取是动画系统获取动画的起点/终点。通常,这是一个计算得出的变量(尽管不一定必须如此)。
    我们可能不希望在Shape / VM代码中使用名称“ animatableData”(我们想使用更能说明数据对我们而言的变量名)。 因此,获取/设置通常只是获取/设置一些其他变量

    相关文章

      网友评论

        本文标题:使用Apple最新的Swift UI技术编写更好的app(6)

        本文链接:https://www.haomeiwen.com/subject/hixxuktx.html