首页 > 解决方案 > Swift UI - 在 gridstack 中为单个视图设置动画

问题描述

我正在尝试解决以下问题。

我有一个生成视图数组的 GridStack 视图。见下文:

struct GridStack<Content: View> : View {
    let rows :Int
    let columns : Int
    let content : (Int, Int) -> Content
    
    var body: some View {
        VStack{
            ForEach(0 ..< rows){ row in
                HStack{
                    ForEach(0 ..< columns){ column in
                        self.content(row, column)
                    }
                }
            }
        }
    }
}

我目前有这个工作代码,它将数组的值发送到我的主代码中的整数变量“upTo”中:

GridStack(rows: 3, columns: 4){ rows, cols in
          Button(action: {
                 upTo = rows * 4 + cols + 1
          }, label: {
                 Text("Number \(rows * 4 + cols + 1)")
          })
}

我想让这个文本动画,但是如果我直接向文本添加动画,每一个文本都会在点击时移动,我只想为我点击的那个动画。

我试图将文本变成按钮视图并将其传递到主按钮的标签中,但显然嵌入按钮是一种可判处死刑的罪行。

有没有人有任何想法?提前致谢!

标签: buttonviewswiftuiaction

解决方案


我认为两种解决方案是可行的。请在下面查看我的工作示例。

您希望单击按钮后应用的效果保持不变吗?在这种情况下,我建议创建一个存储状态的自定义视图。

struct GridStack<Content: View> : View {
    let rows :Int
    let columns : Int
    let content : (Int, Int) -> Content
    
    var body: some View {
        VStack{
            ForEach(0 ..< rows){ row in
                HStack{
                    ForEach(0 ..< columns){ column in
                        self.content(row, column)
                    }
                }
            }
        }
    }
}

struct MyCustomView: View {
    let upTo: Int
    let callback: () -> Void
    
    @State var animate = false
    
    var body: some View {
        Button(action: {
            self.callback()
            self.animate.toggle()
        }) {
            Text("Number \(self.upTo)")
                .background(self.animate ? Color.red : Color.white)
                .animation(.linear(duration: 1.0))
        }
    }
}

struct ContentView2: View {
    @State var upTo: Int = 0
    
    var body: some View {
        VStack {
            Text("\(self.upTo)")

            GridStack(rows: 3, columns: 4) { rows, cols in
                MyCustomView(upTo: rows * 4 + cols + 1, callback: {
                    self.upTo = rows * 4 + cols + 1
                })
            }
        }
    }
}

struct ContentView2_Previews: PreviewProvider {
    static var previews: some View {
        ContentView2()
    }
}

否则,自定义按钮样式就可以了。在这种情况下,您可以访问配置的isPressed属性。

struct GridStack<Content: View> : View {
    let rows :Int
    let columns : Int
    let content : (Int, Int) -> Content
    
    var body: some View {
        VStack{
            ForEach(0 ..< rows){ row in
                HStack{
                    ForEach(0 ..< columns){ column in
                        self.content(row, column)
                    }
                }
            }
        }
    }
}

struct MyCustomButtonStyle: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .background(configuration.isPressed ? Color.red : Color.white)
            .animation(.linear(duration: 1.0))
    }
}

struct ContentView2: View {
    @State var upTo: Int = 0
    
    var body: some View {
        VStack {
            Text("\(self.upTo)")

            GridStack(rows: 3, columns: 4) { rows, cols in
                Button(action: {
                    self.upTo = rows * 4 + cols + 1
                }) {
                    Text("Number \(rows * 4 + cols + 1)")
                }
                .buttonStyle(MyCustomButtonStyle())
            }
        }
    }
}

struct ContentView2_Previews: PreviewProvider {
    static var previews: some View {
        ContentView2()
    }
}

推荐阅读