【问题标题】:SwiftUI Button tap only on text portionSwiftUI 按钮仅点击文本部分
【发布时间】:2019-12-11 12:00:30
【问题描述】:

我的按钮的背景区域未检测到用户交互。与所述按钮交互的唯一方法是点击按钮的文本/标签区域。如何使整个 Button 可点击?

struct ScheduleEditorButtonSwiftUIView: View {

    @Binding  var buttonTagForAction : ScheduleButtonType
    @Binding  var buttonTitle        : String
    @Binding  var buttonBackgroundColor : Color


    let buttonCornerRadius = CGFloat(12)

    var body: some View {

        Button(buttonTitle) {
              buttonActionForTag(self.buttonTagForAction)
        }.frame(minWidth: (UIScreen.main.bounds.size.width / 2) - 25, maxWidth: .infinity, minHeight: 44)

                            .buttonStyle(DefaultButtonStyle())
                            .lineLimit(2)
                            .multilineTextAlignment(.center)
                            .font(Font.subheadline.weight(.bold))
                            .foregroundColor(Color.white)

                            .border(Color("AppHighlightedColour"), width: 2)
                           .background(buttonBackgroundColor).opacity(0.8)

                            .tag(self.buttonTagForAction)
                            .padding([.leading,.trailing], 5)
       .cornerRadius(buttonCornerRadius)

    }
}

【问题讨论】:

标签: swiftui


【解决方案1】:

我认为这是一个更好的解决方案,将.frame 值添加到Text() 并且按钮将覆盖整个区域?

Button(action: {
    //code
}) {
    Text("Click Me")
    .frame(minWidth: 100, maxWidth: .infinity, minHeight: 44, maxHeight: 44, alignment: .center)
    .foregroundColor(Color.white)
    .background(Color.accentColor)
    .cornerRadius(7)
}

【讨论】:

  • 很好的解决方法。
  • 这不适用于 Xcode 11.5 beta。我尝试了两种方法,一种在答案中,也将大小移动到自定义 ButtonStyle
【解决方案2】:

正确的解决方案是使用.contentShape() API。

Button(action: action) {
  HStack {
    Spacer()
    Text("My button")
    Spacer()
  }
}
.contentShape(Rectangle())

您可以更改提供的形状以匹配按钮的形状;如果您的按钮是 RoundedRectangle,您可以提供它。

【讨论】:

  • 是的,这是真正的答案,无论您是否有背景颜色,它都有效。
  • 将 .contentShape(Rectangle()) 添加到 HStack 内部按钮对我有用
  • 这是唯一对我有用的解决方案,除了我必须把它放在按钮内的堆栈上,而不是放在按钮本身上。
  • 如果您使用自定义 ButtonStyle,则其他解决方案不起作用。这是问题的真正解决方案。
【解决方案3】:

这解决了我的问题:

var body: some View {
    GeometryReader { geometry in
        Button(action: {
            // Action
        }) {
            Text("Button Title")
                .frame(
                    minWidth: (geometry.size.width / 2) - 25,
                    maxWidth: .infinity, minHeight: 44
                )
                .font(Font.subheadline.weight(.bold))
                .background(Color.yellow).opacity(0.8)
                .foregroundColor(Color.white)
                .cornerRadius(12)

        }
        .lineLimit(2)
        .multilineTextAlignment(.center)
        .padding([.leading,.trailing], 5)
    }
}

您使用UIScreen 而不是GeometryReader 有什么原因吗?

【讨论】:

  • 不知道 GeometryReader。感谢您提供的信息,我将阅读它
  • 很好的答案。我在按钮本身上有大小修饰符,而不是文本:)
【解决方案4】:

您可以通过添加修饰符来定义命中测试的内容形状:contentShape(_:eoFill:)

重要的是你必须在 Button 的内容中应用。

Button(action: {}) {
    Text("Select file")
       .frame(width: 300)
       .padding(100.0)
       .foregroundColor(Color.black)
       .contentShape(Rectangle()) // Add this line
}
.background(Color.green)
.cornerRadius(4)
.buttonStyle(PlainButtonStyle())

另一个

Button(action: {}) {
    VStack {
       Text("Select file")
           .frame(width: 100)
       Text("Select file")
           .frame(width: 200)
    }
    .contentShape(Rectangle())
}
.background(Color.green)
.cornerRadius(4)
.buttonStyle(PlainButtonStyle())

【讨论】:

    【解决方案5】:

    简答

    确保Text(或按钮内容)跨越触摸区域的长度,并使用.contentShape(Rectangle())

    Button(action:{}) {
      HStack {
        Text("Hello")
        Spacer()
      }
      .contentShape(Rectangle())
    }
    

    长答案

    分为两部分:

    1. Button 的内容(例如 Text)需要拉伸
    2. 命中测试需要考虑内容

    拉伸内容(例如Text):

    // Solution 1 for stretching content
    HStack {
      Text("Hello")
      Spacer()
    }
    
    // Solution 2 for stretching content
    Text("Hello")
      .frame(maxWidth: .infinity, alignment: .leading)
    
    // Alternatively, you could specify a specific frame for the button.
    

    要考虑命中测试使用.contentShape(Rectangle())的内容:

    // Solution 1
    Button(action:{}) {
      HStack {
        Text("Hello")
        Spacer()
      }
      .contentShape(Rectangle())
    }
    
    // Solution 2
    Button(action:{}) {
      Text("Hello")
        .frame(maxWidth: .infinity, alignment: .leading)
        .contentShape(Rectangle())
    }
    

    【讨论】:

      【解决方案6】:

      答案有点晚了,但我找到了两种方法——

      选项 1:使用几何阅读器

      Button(action: {
      }) {
          GeometryReader { geometryProxy in
              Text("Button Title")
                  .font(Font.custom("SFProDisplay-Semibold", size: 19))
                  .foregroundColor(Color.white)
                  .frame(width: geometryProxy.size.width - 20 * 2) // horizontal margin
                  .padding([.top, .bottom], 10) // vertical padding
                  .background(Color.yellow)
                  .cornerRadius(6)
          }
      }
      

      选项 2:将 HStack 与 Spacers 一起使用

      HStack {
          Spacer(minLength: 20) // horizontal margin
          Button(action: {
      
          }) {
              Text("Hello World")
                  .font(Font.custom("SFProDisplay-Semibold", size: 19))
                  .frame(maxWidth:.infinity)
                  .padding([.top, .bottom], 10) // vertical padding
                  .background(Color.yellow)
                  .foregroundColor(Color.white)
                  .cornerRadius(6)
          }
          Spacer(minLength: 20)
      }.frame(maxWidth:.infinity)
      

      我在这里的思考过程是,虽然选项 1 更简洁,但我会选择选项 2,因为它与其父级的大小(通过 GeometryReader)的耦合较小,而且更符合我认为 SwiftUI 旨在使用 @987654324 的方式@、VStack

      【讨论】:

      • 如何让整个按钮对点击事件敏感,而不仅仅是文本内容?
      • 对我来说第二个选项更好。
      【解决方案7】:

      您可能正在这样做:

      Button { /*to do something on button click*/} 
      label: { Text("button text").foregroundColor(Color.white)}
      .frame(width: 45, height: 45, alignment: .center)
      .background(Color.black)
      

      解决方案:

      Button(action: {/*to do something on button click*/ }) 
      { 
      HStack { 
      Spacer()
      Text("Buttton Text")
      Spacer() } }
      .frame(width: 45, height: 45, alignment: .center)
      .foregroundColor(Color.white)
      .background(Color.black).contentShape(Rectangle())
      

      【讨论】:

        猜你喜欢
        • 2018-12-10
        • 1970-01-01
        • 1970-01-01
        • 2021-03-21
        • 2020-08-19
        • 2022-01-03
        • 2020-06-07
        • 1970-01-01
        • 2012-02-22
        相关资源
        最近更新 更多