具有切换子视图和选择手势的列表项

Posted

技术标签:

【中文标题】具有切换子视图和选择手势的列表项【英文标题】:List Item with Toggle subview and selection gesture 【发布时间】:2021-01-06 07:32:26 【问题描述】:

我有一个包含Toggle 视图的列表和项目。我想分别处理选择和切换状态。未选择列表项时应禁用切换。 问题是:

    第一次点击 - 选择列表项。 (selected = true) 点击切换 - 设置selection = false

在 UIKit 上,Button/Switch/etc...抓住“点击”,不要进入 TableView 选择状态。

struct ListView: View 
    @State var selected = Set<Int>()
    let items = (1...10).map  ItemDataModel(id: $0) 
    
    var body: some View 
        List(items)  item in
            ListItemView(dataModel: item)
                .onTapGesture  if !(selected.remove(item.id) != .none)  selected.insert(item.id) 
        
    


struct ListItemView: View 
    @ObservedObject var dataModel: ItemDataModel
    
    var body: some View 
        HStack 
            Text(dataModel.title)
            Spacer()
            Toggle(
                isOn:Binding<Bool>(get: dataModel.isOn, set: dataModel.isOn = $0),
                label:  Text("toggle") )
        
    


class ItemDataModel: Hashable, Identifiable, ObservableObject 
    let id: Int
    let title: String
    @Published var isOn: Bool = false
    
    init(id: Int) 
        self.id = id
        title = "item \(id)"
    
    
    func hash(into hasher: inout Hasher) 
        hasher.combine(title)
    
    
    static func == (lhs: ItemDataModel, rhs: ItemDataModel) -> Bool 
        return lhs.id == rhs.id
    

[请尝试忽略语法错误(如果存在)并专注于手势问题]

【问题讨论】:

【参考方案1】:

首先,您的[ItemDataModel] 数组应该移到正文之外,因此不会每次都重新创建:

struct ListView: View 
    @State var selected = Set<Int>()
    let items = (1...10).map(ItemDataModel.init) // move outside the `body`

    var body: some View 
        VStack 
            Text(String(describing: selected))
            List(items)  item in
                ListItemView(dataModel: item)
                    .onTapGesture  if !(selected.remove(item.id) != .none)  selected.insert(item.id) 
            
        
    

然后,确保 ListItemView 中的 Toggle 不会占用所有空间(这是默认行为)并附加 onTapGesture 以覆盖父母的手势:

struct ListItemView: View 
    @ObservedObject var dataModel: ItemDataModel

    var body: some View 
        HStack 
            Text(dataModel.title)
            // Text("toggle") // if necessary add Toggle's label as `Text`
            Spacer()
            Toggle("", isOn: $dataModel.isOn) // use another initialiser
                .fixedSize() // limit Toggle's width
                .background(Color.red) // debug-only, to see the real frame
                .onTapGesture  // override tap gestures
        
        .contentShape(Rectangle()) // make empty space *clickable*
    

【讨论】:

如果我为Toggle明确实现onTapGesture,当我点击它时,将调用切换'onTap'而不会调用超级视图的'onTap'? 我对@9​​87654330@ 有同样的问题。用Picker (SegmentedPickerStyle) 替换Toggle,现在添加onTap 会禁用单元格选择(如我所愿),但也会禁用picker 操作。我尝试将onTap 单独设置为每个段,但这也不起作用。 @gutte 请用您的新问题创建一个新帖子。我会尽力为您提供帮助(创建后,您可以在此处 ping 链接)。 这是我的第二个问题:***.com/questions/66516795/…@pawello2222

以上是关于具有切换子视图和选择手势的列表项的主要内容,如果未能解决你的问题,请参考以下文章

在具有相同触摸的视图上切换手势

具有 UIView 作为子视图的 UICollectionView 的选择性手势识别

如何在列表视图索引中切换子元素的可见性?

通过子组件在父组件中反应切换视图功能

选择导航列表项时需要切换“活动”类

如何将手势切换回上一个视图 ios?