0

我正在尝试将square下面的两个正方形从一个共同的中心点动画到它们出现时的最终位置,然后返回 - 当它们被移除时。

这是我尝试过的,但结果是它们不是从重叠位置开始的 - 相反,它们从靠近中心的每个位置开始:

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 回答