SwiftUI学习(6)-SwiftUI动画入门上

SwiftUI学习(6)-SwiftUI动画入门上

2021, Apr 28    

コニクマル撰写

本文使用目前最新版本的xcode 12 + macOS Big sur + iOS14

SwiftUI和UIKit一样提供了显式(Explicit)和隐式(Implicit )动画。

显式动画

在UIKit中显式动画通过UIView.animate来触发, 如下

UIView.animate(withDuration: 0.5) {
    someview.alpha = 0
}

在SwiftUI中则使用withAnimation来完成显式动画,举个例子:

@State var alphaValue: Double = 1
  var body: some View {
      VStack {
          Text("Hello, World!")
              .opacity(self.alphaValue)
              .padding()

          Button("启动") {
              withAnimation(.easeIn(duration: 0.5)) {
                  self.alphaValue = 0
              }
          }
      }
  }

2021-05-09 -2003.36

隐式动画

通过设置Viewanimation装饰器(modifier), 当View相关的属性值变化后,提供会自动添加过渡的动画。比如

@State var isClicked: Bool = false
var body: some View {
    VStack {
        RoundedRectangle(cornerRadius: 25)
            .foregroundColor(self.isClicked ? .red : .green)
            .frame(width: self.isClicked ? CGFloat(300.0) : CGFloat(200.0), height: 200)
            .padding()
            .animation(.default)
        Button("启动") {
            self.isClicked.toggle()
        }
    }
}

运行效果如果下:

2021-05-09-20-16-50

Animation结构体

系统的Animation结构体为我们提供一些常用的动画比如easeOut ` easeIn easeInOut spring等常用的动画。无论显式还是隐式动画都需要使用到Animation可以通过直接传入Animation`静态成员,

RoundedRectangle(cornerRadius: 25)
		....
    .animation(Animation.easeOut)

也可以调用Animation的静态方法设置一些参数比如设置动画时间1秒

RoundedRectangle(cornerRadius: 25)
		....
    .animation(Animation.easeOut(duration: 1))

重复动画

Animation具有repeatForever repeatCount的装饰器可以用来完成一些循环动画比如:

@State var isClicked: Bool = false
var body: some View {
    VStack {
        Image(systemName: "suit.heart.fill")
            .resizable()
            .scaledToFit()
            .foregroundColor(.red)
            .frame(width: 200, height: 200, alignment: .center)
            .scaleEffect(self.isClicked ? 0.5: 1)
            .animation(Animation.linear(duration: 0.5).repeatForever())
            .padding()

        Button("启动") {
            self.isClicked.toggle()
        }
        .padding()
    }
}

效果如下

2021-05-09-20-45-00

延迟动画

Animationdelay装饰器可以延迟动画启动时间,对于多个View的联合的动画相当有用, 比如实现各加载的indicator:

@State var isClicked: Bool = false
var body: some View {
  VStack {
      HStack{
          let scale: CGFloat = isClicked ? 0 : 1
          ForEach(0 ..< 5){ index in
              Circle()
                  .frame(width: 50, height: 50, alignment: .center)
                  .scaleEffect(scale)
                  .foregroundColor(.red)
                  .animation(Animation.linear(duration: 0.8).repeatForever().delay(0.2 * Double(index)))
          }
      }

      Button("启动") {
          self.isClicked.toggle()
      }
      .padding()
  }
}

效果如下:

2021-05-09-20-54-35