【问题标题】:Insertion/Removal animation in SwiftUISwiftUI 中的插入/移除动画
【发布时间】:2021-04-21 08:34:53
【问题描述】:

我正在尝试实现此动画以在VStack 中插入元素,所有元素向下移动以为新元素创建空间,然后从右向左插入新元素。 下面的代码按照我的描述进行插入,但是如何使它也可以用于移除,动画应该类似,元素被完全移除(向右),然后其他元素向上移动)

struct ContentView: View {
    
    @State var show = false
    
    var body: some View {
        VStack {
            
            show ? Rectangle().frame(width: 100, height: 100, alignment: .center)
                .animation(Animation.easeIn(duration: 0.5).delay(1))
                .transition(.move(edge: .trailing)): nil
            
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            Rectangle().frame(width: 100, height: 100, alignment: .center)
            
            Button("Add") {
                show.toggle()
            }
            Spacer()
            
        }.animation(Animation.easeIn(duration: 0.5))
    }
}

【问题讨论】:

    标签: ios swift animation swiftui


    【解决方案1】:

    如果你有那么多Rectangle()s,你应该使用ForEach。这将使添加和删除它们变得更加容易,因为您只需 appendremoveLast 即可更改显示的数量。

    这就是我所做的:

    1. 创建一个表示Rectangle 的新结构
    2. added 属性将控制是否显示Rectangle
    3. 定义将向用户显示的RectangleInfo 数组
    4. 使用ForEach 循环遍历rectangles
    5. 除了transition,您可以使用offset 来更好地控制动画。

    设置好 UI 后,就该制作动画了:

    1. 首先附加一个矩形,为其腾出空间
    2. 添加后,将 added 设置为 true,以便它滑入
    3. added 设置为 false 以将其滑出
    4. 一旦滑出,将其从阵列中移除并移除空间。
    struct RectangleInfo: Identifiable { /// 1.
        let id = UUID()
        var added = true /// 2.
    }
    
    struct ContentView: View {
        
        @State var rectangles = [ /// 3.
            RectangleInfo(),
            RectangleInfo(),
            RectangleInfo()
        ]
        
        let animationDuration = 0.5
        
        var body: some View {
            VStack {
                
                ForEach(rectangles) { rectangle in /// 4.
                    Rectangle().frame(width: 100, height: 100, alignment: .center)
                        .offset(x: rectangle.added ? 0 : 200, y: 0) /// 5.
                }
                
                Button("Add") {
                    rectangles.append(RectangleInfo(added: false)) /// 6.
                    DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
                        rectangles[rectangles.count - 1].added = true /// 7.
                    }
                }
                Button("Remove") {
                    rectangles[rectangles.count - 1].added = false /// 8.
                    DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
                        rectangles.removeLast() /// 9.
                    }
                }
                
                Spacer()
                
            }.animation(Animation.easeIn(duration: animationDuration))
        }
    }
    

    结果:

    【讨论】:

      【解决方案2】:

      我不确定您的最终结果究竟应该是什么,而且我提出的解决方案并不是真正的“通用”,但它至少应该为您提供一个起点。

      struct ContentView: View {
          
          @State var show = false
          @State var showPlaceholder = false
          
          // The total animation duration will be twice as long as this value
          private var animationDuration: TimeInterval = 0.5
          
          var body: some View {
              VStack {
                  
                  ZStack {
                      if showPlaceholder {
                          Color.white.opacity(0.0)
                              .zIndex(1)
                              .frame(width: 100, height: 100)
                      }
                      if show {
                          Rectangle()
                              .zIndex(2)
                              .frame(width: 100, height: 100, alignment: .center)
                              .animation(Animation.easeIn(duration: animationDuration))
                          .transition(.move(edge: .trailing))
                      }
                  }
                  
                  Rectangle().frame(width: 100, height: 100, alignment: .center)
                  Rectangle().frame(width: 100, height: 100, alignment: .center)
                  Rectangle().frame(width: 100, height: 100, alignment: .center)
                  Rectangle().frame(width: 100, height: 100, alignment: .center)
                  
                  Button("Add") {
                      if show {
                          showPlaceholder(for: animationDuration)
                          show = false
                      }
                      else {
                          showPlaceholder(for: animationDuration) {
                              show = true
                          }
                      }
                  }
                  Spacer()
                  
              }.animation(Animation.easeIn(duration: animationDuration))
          }
          
          private func showPlaceholder(for timeInterval: TimeInterval, completion: (() -> Void)? = nil) {
              showPlaceholder = true
              Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { (_) in
                  showPlaceholder = false
                  completion?()
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-12
        • 1970-01-01
        • 1970-01-01
        • 2018-07-29
        • 2012-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多