【问题标题】:Issue with Buttons in SwiftUI on MacOSMacOS 上 SwiftUI 中的按钮问题
【发布时间】:2020-02-13 13:55:29
【问题描述】:

我在 MACOS 上使用 SwiftUI

如果我这样做:

      Button(action: { } ) {
        Text("Press")
        .padding()
        .background(Color.blue)
      }

我明白了:

两个灰色区域是可点击按钮的末端。 但我希望按钮是蓝色区域的形状。 任何想法如何让整个蓝色区域都可以点击。

(我确实看过使用 .onTapGesture 但这不会为按钮设置动画,因此您知道您已经点击了它。)

【问题讨论】:

标签: macos button swiftui


【解决方案1】:

您可以通过添加 .buttonStyle(.borderless) 在 macOS 上“强制”类似 iOS 的行为。

Button(action: { } ) {
   Text("Press")
      .padding()
      .background(Color.blue)
}
.buttonStyle(.borderless)

【讨论】:

    【解决方案2】:

    我在反馈助手上向 Apple 提出了这个问题,看看他们是否有任何有用的想法。

    在此对话:

    我说:

    如果在带有 SwiftUI 的 MACOS 上,我会这样做:

      Button(action: { } ) {
        Text("Press")
        .padding()
        .background(Color.blue)
      }
    

    我得到一个蓝色的盒子,两边有两个灰色的小点。 附图片。 这是两个灰色区域,是可点击按钮的末端。但我希望按钮是蓝色区域的形状。

    相同的代码在 iOS 上可以正常工作。

    (我确实看过使用 .onTapGesture 但这不会为按钮设置动画,因此您知道您已经点击了它。)

    苹果说:

    iOS 和 macOS 有不同的默认按钮样式——iOS 是无边框的,macOS 有标准的边框效果。

    听起来您正在尝试创建自定义 ButtonStyle(因此没有任何系统提供的 chrome)。所以你要创建它,它可以将蓝色背景应用到按钮的标签上,然后将它应用到带有文本的简单按钮上,例如

    Button("Press"), action {}).buttonStyle(BluePaddingButtonStyle()
    

    这将确保它在您运行它的每个平台上都具有相同的外观。

    我说:

    您好,感谢您的解释。 我明白你在说什么,我对我想出的方法感到满意。

    这似乎仍然不对:

      Button(action: { } ) {
        Text("Press")
        .padding()
        .background(Color.blue)
      }
    

    应该会产生一些看起来很奇怪的东西。 我不明白为什么那段代码不能只生成一个蓝色按钮。

    正如我所说 - 这不是问题,因为我已经解决了它,但它 目前看起来并不直观。

    苹果说:

    ViewBuilder 中提供的内容用作按钮的标签:而不是整个按钮。按钮仍将带有周围的背景、边框、前景样式等,如 ButtonStyle 所述。因此,如果您的按钮需要具有非常特定的外观,那么它需要自定义该样式:要么是无边框按钮样式(但请注意,它仍然带有特定的前景外观样式),要么是自定义按钮样式。

    我的想法:

    这确实帮助我理解了为什么它会这样显示,但直觉上它似乎仍然是错误的!!!

    【讨论】:

    • 这是有用的见解。感谢分享。
    【解决方案3】:

    受到@Gene Z. Ragan 的精彩回答的启发,我从这个答案开始,并更进一步:

    让 ButtonStyle 更灵活一点:

    struct NiceButtonStyle: ButtonStyle {
      var foregroundColor: Color
      var backgroundColor: Color
      var pressedColor: Color
    
      func makeBody(configuration: Self.Configuration) -> some View {
        configuration.label
          .font(.headline)
          .padding(10)
          .foregroundColor(foregroundColor)
          .background(configuration.isPressed ? pressedColor : backgroundColor)
          .cornerRadius(5)
      }
    }
    

    然后加点糖,让通话现场更干净:

    extension View {
      func niceButton(
        foregroundColor: Color = .white,
        backgroundColor: Color = .gray,
        pressedColor: Color = .accentColor
      ) -> some View {
        self.buttonStyle(
          NiceButtonStyle(
            foregroundColor: foregroundColor,
            backgroundColor: backgroundColor,
            pressedColor: pressedColor
          )
        )
      }
    }
    

    然后意味着我们可以使用默认颜色: 白色前景,灰色背景和重音颜色pressedColor

      Button(action: { } ) {
        Text("Button A")
      }
      .niceButton()
    

    或者我们可以自定义颜色:

      Button(action: { } ) {
        Text("Button B has a long description")
      }
      .niceButton(
        foregroundColor: .blue,
        backgroundColor: .yellow,
        pressedColor: .orange
      )
    

    我们得到:

    再次感谢吉恩。

    【讨论】:

    【解决方案4】:

    您可以通过使用ButtonStyle,然后根据传入的配置值指定颜色和其他样式属性来实现您想要的外观。

    如果有一个快乐的媒介,你可以继承默认按钮半径、基于文本长度和其他属性的自动宽度,那就太好了,但至少可以指定所有属性并获得你的外观想要。

    希望这会有所帮助!

    import SwiftUI
    
    struct BlueButtonStyle: ButtonStyle {
        func makeBody(configuration: Self.Configuration) -> some View {
            configuration.label
                .foregroundColor(configuration.isPressed ? Color.blue : Color.white)
                .background(configuration.isPressed ? Color.white : Color.blue)
                .cornerRadius(6.0)
                .padding()
        }
    }
    
    struct ContentView: View {
        var body: some View {
            VStack {
                Text("Hello World")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
    
                Button(action: {
                }) {
                    Text("Press")
                        .frame(maxWidth: 100, maxHeight: 24)
                }
                .buttonStyle(BlueButtonStyle())
            }
        }
    }
    
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    

    【讨论】:

    • 谢谢@Gene Z. Ragan - 很享受 :-) 有兴趣看看 Apple 是否回应我的反馈。
    • 如果他们回复您,请发表评论。很高兴这对你有用!
    • 会的。从您的良好基础出发,我进一步改进了它,使其更清洁、更灵活。我将作为单独的答案发布。
    • 谢谢大家!这在专家们的脑海中是如此的深藏不露......是否有任何关于 MacOS 上 SwiftUI 限制的文档或论坛,因为大多数教程都是关于 iOS 的,我浪费了时间来追踪这个 macOS 问题。
    【解决方案5】:

    我认为这是不可能的,但您可以尝试使用 this

    支持 SPM,专为 Swift 5.1 构建且精简

    【讨论】:

    • 谢谢@krjw - 非常感谢。 CustomButton 看起来不错,但我不知道如何将它变成与 SwiftUI 一起使用的视图?
    • 我还认为我的问题中的代码似乎是合理的 - 你同意这实际上是一个错误吗?
    • 说实话,我只在 iOS 上使用过 SwiftUI,只是在一个新项目中尝试了你的代码,看看它是否有助于将修饰符应用于按钮本身......我玩了一下位并认为这不是正确的行为。我不会说这是一个错误,因为我不知道预期的行为,但至少对我来说这似乎是错误的
    • 我也一直在 iOS 中使用 Button,它运行良好。我很惊讶它在 MacOS 上没有相同或至少相似的结果,因为 SwiftUI 理念的一部分是您可以使用相同的代码在平台之间移动。
    • 你知道我将如何让 CustomButton 与 SwiftUI 一起工作吗?我想我需要某种符合 View 的包装器?
    猜你喜欢
    • 2022-01-03
    • 2020-12-30
    • 2021-12-22
    • 2020-06-07
    • 2020-04-22
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2020-04-11
    相关资源
    最近更新 更多