0

square下の 2 つの正方形を、共通の中心点から、それらが表示されたときの最終的な位置まで、および削除されたときに戻るようにアニメーション化しようとしています。

これが私が試したものですが、その結果、重複する位置から開始するのではなく、中央のそれぞれの近くから開始します。

struct ContentView: View {
   @State var matched = true
   @State var show = false
   @Namespace var ns
    
   var body: some View {
      VStack {
         HStack {
            Spacer()
            if show {
               square
                  .matchedGeometryEffect(id: matched ? "match" : "", 
                                         in: ns, anchor: .center, isSource: false)
                  .animation(.easeIn)
                  .transition(.move(edge: .trailing ))
                  .onAppear { withAnimation { matched = false } }                        
                  .onDisappear { withAnimation { matched = true } }
            }
            Spacer()
               .matchedGeometryEffect(id: "match", in: ns, anchor: .center, isSource: true)   
            if show {
               square
                  .matchedGeometryEffect(id: matched ? "match" : ""
                                         in: ns, anchor: .center, isSource: false)
                  .animation(.easeIn)
                  .transition(.move(edge: .leading))
            }
            Spacer()
         }
         Button("show") { withAnimation { show.toggle() } }
      }
   }
}

正方形squareは単純に次のように定義されます。

var square: some View {
   Rectangle().foregroundColor(.blue)
      .frame(width: 40, height: 40, alignment: .center)
}

matchedGeometryEffectどのような作業が行われたかは、 内のオーバーレイにアタッチし、それらすべてでSpacer明示的に指定properties: .positionすることでした。

それでも、それらが表示されたときにのみ機能し、消えるときは機能しません。そこにはまだギャップがあります。

Spacer().overlay(
   Color.clear
     .matchedGeometryEffect(id: "match", in: ns, properties: .position, anchor: .center, isSource: true)
   )

これは、この効果を達成するための正しい一般的なアプローチですか?もしそうなら、どうすればそれを機能させることができますか? それとも私はそれを過度に複雑にしましたか?

4

1 に答える 1

3

同じ寸法で少し単純化された別の透明な正方形に一致するジオメトリを試してください。固有の不透明度遷移があり、これを削除してカラー ブレンド モードに置き換えることができます。

struct ContentView: View {
  //@State var matched = true
  @State private var show = false
  @Namespace private var ns
  
  var body: some View {
    VStack {
      
      HStack {
        Spacer()
        if show {
          Square(color: .blue)
            .matchedGeometryEffect(id: 1, in: ns, isSource: false)
        }
        Spacer()
          .background(Square(color: .clear)
                        .matchedGeometryEffect(id: show ? 0 : 1, in: ns, isSource: true))
        if show {
          Square(color: .red)
            .matchedGeometryEffect(id: 1, in: ns, isSource: false)
        }
        Spacer()
      }
       
      Button("show") { withAnimation { show.toggle() } }
    }
  }
  
  struct Square: View {
    let color: Color
    var width: CGFloat = 40
    var body: some View {
      Rectangle().foregroundColor(color).frame(width: width, height: width)
    }
  }
  
}
于 2021-01-07T17:56:05.020 に答える