如何使用 SwiftUI 在按下按钮时更改图像边框?

How to change border of image in button on press using SwiftUI?

我有一个由图像和一些文本组成的 NavigationLink,我想在按下 link 时更改图像的边框颜色。

这是导航链接:

NavigationLink(destination: TrickSelectView()) {
    HStack{
        Image("learnTricksButton")
            .resizable()
            .clipShape(Circle())
            .overlay(Circle().stroke(Color(red: 0.95, green: 0.32, blue: 0.34), lineWidth: 4))
            .shadow(radius: 7)
            .frame(width: width, height: width)
                                
         VStack{
            Text("Trick")
                .font(.system(.largeTitle, design: .rounded))
                .foregroundColor(Color(red: 0.13, green: 0.15, blue: 0.22))

            Text("Personalise your learning!")
                .font(.system(.subheadline, design: .rounded))
                .foregroundColor(Color(red: 0.28, green: 0.32, blue: 0.37))
          }
     }.padding(.bottom, 50)
}.buttonStyle(LearnButtonEffect())

这是我目前为止获得的按钮样式:

struct LearnButtonEffect: ButtonStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .background(configuration.isPressed ? Color.green.opacity(0.5) : Color.green)
            .shadow(color: Color.gray, radius: 10, x: 0, y: 0)
            .scaleEffect(configuration.isPressed ? 0.9 : 1.0)
    }
}

总的来说,我想知道如何在按钮样式定义中引用 NavigationLink 的特定部分(在本例中是图像的边框)。

因为在 SwiftUI 中,我们不保留对任何视图的任何引用。相反,我们更改值(@State@Binding@ObservableObject@StatObject ..)反映视图。

 struct ContentView: View {
        @State var isActive = false //To start navigation
        @State var isClicked = false //to track wather click
        
        var body: some View {
            NavigationView {
                NavigationLink(
                    destination: Text("Destination"),
                    isActive: $isActive,
                    label: {
                        
                        Button(action: {
                            isActive = true
                            isClicked = true
                        }, label: {
                            HStack{
                                Image("learnTricksButton")
                                    .resizable()
                                    .clipShape(Circle())
                                    .overlay(Circle().stroke(isClicked ? Color.black:Color(red: 0.95, green: 0.32, blue: 0.34), lineWidth: 4))
                                    .shadow(radius: 7)
                                    .frame(width: 100, height: 100)
                                
                                VStack{
                                    Text("Trick")
                                        .font(.system(.largeTitle, design: .rounded))
                                        .foregroundColor(Color(red: 0.13, green: 0.15, blue: 0.22))
                                    
                                    Text("Personalise your learning!")
                                        .font(.system(.subheadline, design: .rounded))
                                        .foregroundColor(Color(red: 0.28, green: 0.32, blue: 0.37))
                                }
                            }.padding(.bottom, 50)
                        })
                        
                    })
                
            }
        }
    }

您可以使用 PrimitiveButtonStyle 并传递特定视图并执行您的操作。

这是演示:

创建样式

struct LearnButtonEffectButtonStyle: PrimitiveButtonStyle {
    var image: Image
    var action: () -> Void
    
    func makeBody(configuration: PrimitiveButtonStyle.Configuration) -> some View {
        ButtonView(configuration: configuration, image: image, action: action)
    }
    
    struct ButtonView: View {
        @State private var pressed = false
        
        let configuration: PrimitiveButtonStyle.Configuration
        let image: Image
        var action: () -> Void
        
        var body: some View {
            return HStack{
                image
                    .resizable()
                    .clipShape(Circle())
                    .overlay(Circle().stroke(self.pressed ? Color.yellow : Color.blue, lineWidth: 4)) // <<- You can change here .overlay(Circle().stroke(self.pressed ? Color.yellow : Color.blue, lineWidth: 4))
                    .shadow(radius: 7)
                    .frame(width: 100, height: 50)
                    .border(self.pressed ? Color.yellow : Color.blue, width: 2) //<<- remove it if not required
                configuration.label
            }
            .padding(.bottom, 50)
            .onLongPressGesture(minimumDuration: 0.2, maximumDistance: .infinity, pressing: { pressing in
                withAnimation(.easeInOut(duration: 0.2)) {
                    self.pressed = pressing
                }
                if !pressing {
                    action()
                }
            }, perform: {
                print("Perform")
            })
            .background(self.pressed ? Color.green.opacity(0.5) : Color.green)
            .shadow(color: Color.gray, radius: 10, x: 0, y: 0)
            .scaleEffect(self.pressed ? 0.9 : 1.0)
        }
    }
}

如何使用?

struct ContentView: View {
    
    @State private var isActive = false
    
    var body: some View {
        NavigationView{
            NavigationLink(destination: Text("test"), isActive: $isActive) {
                VStack{
                    Text("Trick")
                        .font(.system(.largeTitle, design: .rounded))
                        .foregroundColor(Color(red: 0.13, green: 0.15, blue: 0.22))
                    
                    Text("Personalise your learning!")
                        .font(.system(.subheadline, design: .rounded))
                        .foregroundColor(Color(red: 0.28, green: 0.32, blue: 0.37))
                }
            }.buttonStyle(LearnButtonEffectButtonStyle(image: Image("learnTricksButton"), action: {
                self.isActive.toggle()
            }))
        }
    }
}