众所周知,一旦状态值产生改变(使用了动画修改),相关的View就会触发过渡动画。

反常动画现象

从一个异常动画现象中了解【SwiftUI】的动画类型

把动画时长调慢一点可以看到:

从一个异常动画现象中了解【SwiftUI】的动画类型

这个Button在动画过程中,会呈现两个Text

其间Button的代码如下:

Button {
    withAnimation(.easeInOut(duration: 0.5)) {
        name = name == .none ? "迪丽热巴" : .none
    }
} label: {
    Text(name == .none ? "这是谁?" : "回来")
        .font(.title2)
        .frame(width: 100)
}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
.controlSize(.large)

废话不多说,直接解释:这是因为Button中的Text“本来”的变形动画被替换成默许的转场动画了!至于为什么会被替换了呢?首要简略介绍一下SwiftUI的过渡动画类型:

转场动画

动画前后是两个不同的View时,会触发转场动画

会有改变前后的两个View做转场动画(默许淡入淡出):

  • 改变前的View保持在初始方位,默许淡出(alpha 1 –> 0)
  • 改变后的View直接在最终方位,默许淡入(alpha 0 –> 1)

触发场景:

  • @ViewBuilder中结构方位不一样的View:例如if {} else {}等控制语句回来不同的View
  • @ViewBuilder中结构方位一样但id不一样的View

变形动画

动画前后是同一个的View时(初始值或者其Modifier用到的状态值产生了改变),只需能通过核算得出的数值(方位、巨细、角度等),就能触发变形动画

可是,如果SwiftUI不知道怎么做变形动画,就会用默许的转场动画(淡入淡出)来代替!

很明显,文本变形是无法通过核算得出的(除非自定义动画,仅仅文本的变形轨道很复杂)。

处理方案

因为SwiftUI不会做文本变形,因而Button中的Text“本来”的变形动画被替换成默许的转场动画,所以才会有两个Text淡入淡出。

虽然做不了文本变形,但除文本以外的变形动画(方位)SwiftUI还是能做的,仅仅体系默许会把其他能算的变形动画一同疏忽掉了

如何处理?只需告诉SwiftUI不要疏忽其他的变形动画即可:

Button {
    withAnimation(.easeInOut(duration: 0.5)) {
        name = name == .none ? "迪丽热巴" : .none
    }
} label: {
    Text(name == .none ? "这是谁?" : "回来")
        .font(.title2)
        .frame(width: 100)
        // 如果不想要淡入淡出作用就加上这句(PS:要在`.transformEffect`前面移除)
        //.animation(.none, value: name) // 这样文字部分就会直接改变,不会有淡入淡出的作用
        .transformEffect(.identity) // 其他的变形作用给我补上!
}
.buttonStyle(.borderedProminent)
.buttonBorderShape(.capsule)
.controlSize(.large)

最终作用:

从一个异常动画现象中了解【SwiftUI】的动画类型

结论

SwiftUI遇到不会的变形动画(例如文本改变),就会疏忽掉这个View其他的变形动画,直接替换成默许的转场动画:动画前后的两个View分别淡入淡出的作用。

其他

@ViewBuilder中结构方位的注意点:

var body: some View {
    // 这种触发的是转场动画
    if name == .none {
        Color.red
    } else {
        Color.yellow
    }
    // 这种触发的是变形动画
    name == .none ? Color.red : Color.yellow
    // 变形动画 -转-> 转场动画:只需id不一样
    Text(name ?? "null")
        .font(.largeTitle)
        .bold()
        .id(name)
        // transition:自定义转场作用,在转场动画中才有用
        .transition(.scale)
}