【问题标题】:How to add a modifier to any specific buttons inside a ForEach loop for an array of buttons in SwiftUI?如何为 SwiftUI 中的按钮数组的 ForEach 循环内的任何特定按钮添加修饰符?
【发布时间】:2022-01-05 09:07:50
【问题描述】:

如何根据需要为各个按钮添加修饰符?

我有一个ForEach 循环在0..<5 的范围内运行,并且我需要在单击的按钮中添加.rotation3DEffect 的动画,并根据它们的状态在剩余的未单击按钮上添加另一个.opacity

注意:我可以观察按钮操作中的任何状态值,然后将其更改为具有动画,但由于修改器已应用于 Button 本身在 ForEach 循环内,我正在播放动画 应用于 foreach 中的每个按钮。

@State private var rotationDegree = 0.0
@State private var selectedNum = 0
@State private var correctAnswer = 0 // comes from saved data

var body: some View {
    
    ForEach(0..<5) { num in // image as a button, loops through their prefix name
        
        Button {
            selectedNum = (num == correctAnswer) ? num : 0
            withAnimation {
                // once clicked, will animate all 5 buttons, need only this clicked button to animate.
                if (num == correctAnswer) {
                    rotationDegree += 360
                }
            }
            
        } label: {
            
            Image("imageName\(num)")
            
        }
        .rotation3DEffect((.degrees((selectedNum == correctAnswer) ? rotationDegree : 0.0)), axis: (x: 0, y: (selectedNum == correctAnswer) ? 1 : 0, z: 0)) // animation I want to add to a specific button
    }
}

【问题讨论】:

  • 这能回答你的问题吗? SwiftUI - Popover in ForEach Loop
  • 不,我要添加一个代码示例
  • ForEach 中的所有内容都需要进入自己的视图,因此每个循环都有自己的状态,这是相同的答案。在你的情况下 num 将是一个参数
  • 你能详细说明一下吗,你说的我不明白; ..进入自己的视野..
  • 您以错误的方式看待问题。您没有与 5 个Buttons 共享Button 共享@State,因此您需要5 个@State 来单独控制它们。创建一个 SwiftUI View,它的body 中包含ForEachcontent 中的所有代码,它还将具有用于控制动画的@State,以及用于num 的参数。跨度>

标签: animation button foreach swiftui modifier


【解决方案1】:
import SwiftUI

struct AnimatedListView: View {
    var body: some View {
        VStack{
            ForEach(0..<5) { num in
                //The content of the ForEach goes into its own View
                AnimatedButtonView(num: num)
            }
        }
    }
}
struct AnimatedButtonView: View {
    //This creates an @State for each element of the ForEach
    @State private var rotationDegree = 0.0
    //Pass the loops data as a parameter
    let num: Int
    var body: some View {
            Button {
                withAnimation {
                    rotationDegree += 360
                }
            } label: {
                Image(systemName: "person")
                Text(num.description)
            }
            .rotation3DEffect((.degrees(rotationDegree)), axis: (x: 0, y: 1, z: 0))
    }
}
struct AnimatedListView_Previews: PreviewProvider {
    static var previews: some View {
        AnimatedListView()
    }
}

【讨论】:

    【解决方案2】:

    尝试将此添加到您的视图中。

    @State var selectedNum: Int = 0
    

    然后将您的按钮更改为如下所示。

    Button {
      selectedNum = num
    
      withAnimation {
        rotationDegree += 360
      }
    } label: {
            Image("imageName\(num)")
        }
        // Check if the selected button is equal to the num
        .rotation3DEffect((.degrees(selectedNum == num ? rotationDegree : 0.0)), axis: (x: 0, y: 1, z: 0))
    

    不确定rotation3DEffect 是如何工作的。但这里有另一个例子

    .background(selectedNum == num ? .red : .blue)
    

    【讨论】:

    • 我实际上尝试仅在按钮操作后将旋转度设置为 360 度,但这仅在未调用该操作时才有效。一旦 Button 的动作触发,值就会改变并应用于整个 foreach 循环,因为修饰符是在循环内设置的。
    • 我已根据您的回答更新了问题代码。
    • @Aashish 您不想在跟踪器中使用布尔值,一旦单击任何按钮,它将切换它并运行动画。我更新了答案,它对我有用。我只是不知道 rotation3DEffect 是如何工作的。
    • 是的,即使是布尔值也适用于背景修饰符,但不适用于 .rotaion3DEffect 使用 nil 合并对行为没有任何影响。但是,作为公认的答案,我们需要向视图本身添加一个修饰符,然后将它们嵌入到 ForEach 循环中。 && 也非常感谢您的努力。
    猜你喜欢
    • 1970-01-01
    • 2020-05-18
    • 1970-01-01
    • 2020-12-22
    • 2017-10-26
    • 2021-06-30
    • 1970-01-01
    • 2019-12-04
    • 2018-05-02
    相关资源
    最近更新 更多