SwiftUI无法使用HStack的Spacer

时间:2019-07-24 20:47:39

标签: ios swift swiftui

我有一个列表视图,列表的每一行包含一个带有某些文本视图和图像的HStack,如下所示:

HStack{
    Text(group.name)
    Spacer()
    if (groupModel.required) { Text("Required").color(Color.gray) }
    Image("ic_collapse").renderingMode(.template).rotationEffect(Angle(degrees: 90)).foregroundColor(Color.gray)
}.tapAction { self.groupSelected(self.group) }

这似乎很好用,除非当我在文本和图像(Spacer()所在的位置)之间的空白区域中点击时,未注册点击动作。仅当我在文本或图像上点击时,点击动作才会发生。

还有其他人遇到此问题/知道解决方法吗?

9 个答案:

答案 0 :(得分:9)

据我最近了解,还有:

HStack {
  ...
}
.contentShape(Rectangle())
.onTapGesture { ... }

对我来说很好。

答案 1 :(得分:3)

我可以通过将Spacer包裹在ZStack中并添加不透明度非常低的纯色来解决此问题:

ZStack {
    Color.black.opacity(0.001)
    Spacer()
}

答案 2 :(得分:2)

为什么不只使用Button

Button(action: { self.groupSelected(self.group) }) {
    HStack {
        Text(group.name)
        Spacer()
        if (groupModel.required) { Text("Required").color(Color.gray) }
        Image("ic_collapse").renderingMode(.template).rotationEffect(Angle(degrees: 90)).foregroundColor(Color.gray)
    }
}.foregroundColor(.primary)

如果您不希望按钮将强调色应用于Text(group.name),则必须像在示例中一样设置foregroundColor

答案 3 :(得分:2)

基于Jim的答案的简单扩展

extension Spacer {
    /// https://stackoverflow.com/a/57416760/3393964
    public func onTapGesture(count: Int = 1, perform action: @escaping () -> Void) -> some View {
        ZStack {
            Color.black.opacity(0.001).onTapGesture(count: count, perform: action)
            self
        }
    }
}

现在可以使用

Spacer().onTapGesture {
    // do something
}

答案 4 :(得分:1)

我已为此提交了feedback,并建议您也这样做。

与此同时,不透明的Color应该和Spacer一样工作。不幸的是,您将不得不匹配背景色,这假定您在按钮后面没有任何显示。

答案 5 :(得分:1)

我只为clear的作品添加背景色(HStack除外)。

HStack {
        Text("1")
        Spacer()
        Text("1")
}.background(Color.white)
.onTapGesture(count: 1, perform: {

})

答案 6 :(得分:1)

虽然接受的答案允许模仿按钮功能,但在视觉上它并不满足。不要用 Button.onTapGesture 代替 UITapGestureRecognizer,除非您只需要一个接受手指点击事件的区域。此类解决方案被认为是陈旧的,不是好的编程实践。

要解决您的问题,您需要实施 BorderlessButtonStyle ⚠️

示例

创建一个通用单元格,例如SettingsNavigationCell

设置导航单元

struct SettingsNavigationCell: View {
  
  var title: String
  var imageName: String
  let callback: (() -> Void)?

  var body: some View {
    
    Button(action: {
      callback?()
    }, label: {

      HStack {
        Image(systemName: imageName)
          .font(.headline)
          .frame(width: 20)
        
        Text(title)
          .font(.body)
          .padding(.leading, 10)
          .foregroundColor(.black)
        
        Spacer()
        
        Image(systemName: "chevron.right")
          .font(.headline)
          .foregroundColor(.gray)
      }
    })
    .buttonStyle(BorderlessButtonStyle()) // <<< This is what you need ⚠️
  }
}

设置视图

struct SettingsView: View {
  
  var body: some View {
    
    NavigationView {
      List {
        Section(header: "Appearance".text) {
          
          SettingsNavigationCell(title: "Themes", imageName: "sparkles") {
            openThemesSettings()
          }
          
          SettingsNavigationCell(title: "Lorem Ipsum", imageName: "star.fill") {
            // Your function
          }
        }
      }
    }
  }
}

答案 7 :(得分:0)

在每个视图上都像魔术一样工作:

df[4:7] <- lapply(df[4:7], function(x) ifelse(x == 1, df$born, x))

df
#>   name    sex born   v4   v5   v6 v7
#> 1  tim   male 1985 1985    0 1985  0
#> 2  tom   male 1986    0    0    0  0
#> 3  ben   male 1985 1985    0    0  0
#> 4 mary female 1986    0    0 1986  0
#> 5 jane female 1984 1984 1984 1984  0

答案 8 :(得分:0)

有点本着所说的一切精神:

struct NoButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .background(Color.black.opacity(0.0001))
    }
}
extension View {
    func wrapInButton(action: @escaping () -> Void) -> some View {
        Button(action: action, label: {
            self
        })
        .buttonStyle(NoButtonStyle())
    }
}

我创建了 NoButtonStyle 是因为 BorderlessButtonStyle 仍然提供与 .onTapGesture 不同的动画

示例:

HStack {
    Text(title)
    Spacer()
    Text("Select Value")
    Image(systemName: "arrowtriangle.down.square.fill")
}
.wrapInButton {
    isShowingSelectionSheet = true
}

另一种选择:

extension Spacer {
    func tappable() -> some View {
        Color.blue.opacity(0.0001)
    }
}

更新:

我注意到 Color 在放入堆栈时并不总是与 Spacer 相同,所以我建议不要使用该 Spacer 扩展,除非您知道这些差异. (间隔器沿堆栈的单个方向推送(如果在 VStack 中,则垂直推送,如果在 HStack 中,则水平推出,而 Color 视图则向内推出所有方向。)