【问题标题】:How to change a button image when the button is pressed in swiftui如何在swiftui中按下按钮时更改按钮图像
【发布时间】:2020-06-14 06:13:53
【问题描述】:

我想在按下按钮时更改图像名称。

这是我目前的结构:

struct ContentView: View { 
    @State var matrix = [Int] var 
    body: some View { 
        VStack { 
            Text("Test") 
            HStack(alignment: .center, spacing: 8) { 
                Button(action: { 
                    **
                    // call a func that will do some check and 
                    // change the image from Blue.png to Red.png
                    ** 
                }) { 
                    Image("Blue") 
                        .renderingMode(.original)
                        .resizable()                               
                        .aspectRatio(contentMode: .fill)
                        .clipShape(Circle()) 
                } 
            } 
        } 
    } 
 } 

【问题讨论】:

标签: swift image button


【解决方案1】:

我已经四处寻找一个好的解决方案,但它们都有其缺点。我经常看到的一种方法 (here) 围绕在识别用户触摸和释放的按钮内容上创建自定义 ViewModifier 和 DragGesture。这个解决方案有很多问题,主要是手势优先于任何其他手势。这使得无法使用ScrollView 中的按钮。

从 iOS 13.0+ 开始,Apple 提供了一个 ButtonStyle 协议,主要用于快速设置按钮样式。该协议公开了一个完美反映按钮状态的isPressed 变量。我的意思是,当您按住按钮并将手指拖到其视图之外时,变量会从 true 更改为 false,正如您所期望的那样。我链接到的以前的解决方案不是这种情况。

解决问题的方法是先定义一个新的ButtonStyle,绑定变量isPressed:

struct IsPressedRegisterStyle : ButtonStyle {
    @Binding var isPressed : Bool
    func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
            .onChange(of: configuration.isPressed, perform: {newVal in
                isPressed = newVal
            })
    }
}

然后使用这个样式:

struct IconButton : View {
    @State var width: CGFloat? = nil
    @State var height: CGFloat? = nil
    let action : () -> Void
    
    @State private var isPressed : Bool = false
    
    var body : some View {
        Image(isPressed ? "someImage" : "someOtherImage")
            .renderingMode(.original)
            .resizable()
            .scaledToFit()
            .frame(width: width, height: height)
            .overlay{
                GeometryReader{proxy in
                    Button(
                        action:{
                            action()
                        },
                        label: {
                            Spacer()
                                .frame(width: proxy.size.width, height: proxy.size.height)
                                .contentShape(Rectangle())
                        })
                        .buttonStyle(IsPressedRegisterStyle(isPressed: $isPressed))
                }
            }
    }
}

注意在其定义底部使用自定义ButtonStyle。

这里只是快速浏览一下到底发生了什么:

  • 我们创建一个 Image 并覆盖一个 Button,使用一个垫片覆盖整个区域。
  • 按下图像会触发叠加按钮。
  • 我们应用的自定义ButtonStyle 将按钮的内部isPressed 变量暴露给我们的IconButton 视图。
  • 我们根据曝光值设置按钮图片。

你像这样实例化一个按钮:

// arbitrary values for width and height
IconButton(width: 200, height: 70){
    print("Button Pressed")
}

我没有对这段代码进行太多测试,所以如果使用它有任何缺点,请告诉我。

干杯!

【讨论】:

  • 欢迎来到 Stack Overflow 社区,@Hkon。这是一个特殊的第一个答案,并提供了我们希望在这里看到的详细程度和解释。继续努力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多