SwiftUI - アニメーションで遊ぶ

1. アニメーションを使って階層リストを作成してみる

alt

Listには、階層リストを出力する方法(Listの使い方)がありますが、ここではアニメーションを使用して独自に階層リストを作成してみました。withAnimation()Text("Children")のアニメーションをコントロールしています。

struct ContentView: View {
  @State private var show = false
  
  var body: some View {
    List {
      HStack {
        Text("List")
        Spacer()
        Button(action: {
          //vvv
          withAnimation(.easeInOut(duration: 0.1)) {
            self.show.toggle()
          }
        }){
          Image(systemName: "chevron.right")
            .font(.system(size: 13, weight: .medium))
            .rotationEffect(.degrees(show ? 90 : 0)) //<<<
            //[Effect]
            //scaleEffect()
            //rotationEffect() 
            //rotation3DEffect()
            //projectionEffect()
            //transformEffect()

            .animation(.easeInOut(duration: 0.1)) //<<<
            //[TypeMethods] 
            //.easeIn()
            //.easeInOut()
            //.easeOut()
            //.linear()
            //.spring()
            //.interactiveSpring()
            //.interpolatingSpring()
            //.timingCurve()
        }
      }
      if show {
        Text("Children")
      }
    }
    .listStyle(InsetGroupedListStyle())
  }
}

2. transitionを使ってみる

alt

struct ContentView: View {
  @State private var show = true
  
  var body: some View {
    HStack {
      Spacer()
      if show {
      Circle()
        .fill(Color.red)
        .frame(width: 200, height: 200)
        .transition(.scale) //<<<
        //[TypeProperties] 
        //.identity
        //.scale
        //.opacity
        //.slide
      }
      Spacer()
      Button(action: {
        //vvv
        withAnimation(.easeInOut(duration: 0.25)) {
        self.show.toggle()
        }
      }){
        Text("Button")
      }
      .padding()
    }
  }
}

3. Spring系のanimationを使ってみる

alt

ばね表現のanimationを使用してみました。springinteractiveSpringは動き自体は同じです。

struct ContentView: View {
  @State private var show = false
  
  var body: some View {
    VStack {
      Spacer()
      Rectangle()
        .stroke(lineWidth: 10)
        .fill(Color.blue)
        .frame(width: 100, height: 100)
        .rotationEffect(.degrees(show ? 765 : 45), anchor: .center)
        .animation(
          .spring(
            response: 1.0, //ばねの剛性
            dampingFraction: 0.4, //抗力の量
            blendDuration: 0.5 //補間する時間
          )
        )
      Spacer()
      Rectangle()
        .stroke(lineWidth: 10)
        .fill(Color.blue)
        .frame(width: 100, height: 100)
        .rotationEffect(.degrees(show ? 765 : 45), anchor: .center)
        .animation(
          .interactiveSpring(
            response: 0.8, //ばねの剛性
            dampingFraction: 0.4, //抗力の量
            blendDuration: 0.8 //補間する時間
          )
        )
      Spacer()
      Rectangle()
        .stroke(lineWidth: 10)
        .fill(Color.blue)
        .frame(width: 100, height: 100)
        .rotationEffect(.degrees(show ? 765 : 45), anchor: .center)
        .animation(
          .interpolatingSpring(
            mass: 1.0, //オブジェクトの質量
            stiffness: 4.0, //ばねの剛性
            damping: 3.0, //ばねの減衰値
            initialVelocity: 3.0 //ばねの初速度
          )
        )
      Spacer()
      Button(action: {
        self.show.toggle()
      }){
        Text("Button")
      }
      Spacer()
    }
  }
}

4. extension化したい場合

transition()extensionを作成する場合

extension AnyTransition {
  static var xxx: AnyTransition {
    ...
  }
}

//Use
.transition(.xxx)

animation()extensionを作成する場合

extension Animation {
  static func xxx() -> Animation {
    ...
  }
}

//Use
.animation(.xxx())

関連する記事>> protocolとextensionについて

Animation | Apple Developer Documentation
Anytransition | Apple Developer Documentation
withAnimation(::) | Apple Developer Documentation