【问题标题】:UITableview: How to Disable Selection for Some Rows but Not OthersUITableview:如何禁用某些行而不是其他行的选择
【发布时间】:2011-01-17 02:26:12
【问题描述】:

我在一组tableview 中显示从 XML 解析的内容。我想禁用它的点击事件(我根本不能点击它) 该表包含两个组。我只想禁用第一组的选择,而不是第二组。点击第二组第一行navigates到我的管player view

我怎样才能只选择特定的组或行?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if(indexPath.section!=0)
    if(indexPath.row==0)    

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:tubeUrl]];   
}

谢谢。

【问题讨论】:

    标签: ios iphone objective-c uitableview


    【解决方案1】:

    您只需将此代码放入cellForRowAtIndexPath

    禁用单元格的选择属性:(点击单元格时)

    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    

    为了能够选择(点击)单元格:(点击单元格)

    // Default style
    cell.selectionStyle = UITableViewCellSelectionStyleBlue;
    
    // Gray style
    cell.selectionStyle = UITableViewCellSelectionStyleGray;
    

    请注意,带有selectionStyle = UITableViewCellSelectionStyleNone; 的单元格在用户触摸时仍会导致 UI 调用didSelectRowAtIndexPath。为避免这种情况,请按照以下建议进行设置。

    cell.userInteractionEnabled = NO;
    

    相反。另请注意,您可能希望将 cell.textLabel.enabled = NO; 设置为灰色项目。

    【讨论】:

    • 这个方法如果滑动删除会产生bug。
    • 这是骇客!这样做,使用下面的答案 - 使用 willSelectRowAtIndexPath 并返回 nil!
    • userInteractionEnabled 的东西不正确,挂钩 willSelectRowAtIndexPath 而不是人们注意到的。
    • 在 iOS 6.0 及更高版本上,tableView:shouldHighlightRowAtIndexPath: 是一个新的UITableViewDelegate 方法,它根据传递的indexPath 是否应突出显示而返回BOOL。如果您正在构建 6.0 及更高版本,我强烈推荐这个新 API。
    • 如果您在 Swift 中执行此操作并且遇到了问题但最终到了这里,您需要设置 cell!.selectionStyle = .None 强制解开单元格,允许您访问其属性。
    【解决方案2】:

    如果您想让一行(或行的子集)不可选择,请实现UITableViewDelegate 方法-tableView:willSelectRowAtIndexPath:(TechZen 也提到过)。如果indexPath 不应可选择,则返回nil,否则返回indexPath。要获得默认选择行为,您只需返回传递给您的 delegate 方法的 indexPath,但您也可以通过返回不同的 indexPath 来更改行选择。

    示例:

    - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // rows in section 0 should not be selectable
        if ( indexPath.section == 0 ) return nil;
    
        // first 3 rows in any section should not be selectable
        if ( indexPath.row <= 2 ) return nil;
    
        // By default, allow row to be selected
        return indexPath;
    }
    

    【讨论】:

    • 小细节:你提醒
    • 我还想补充一点,这是正确的答案,但您还应该在 cellForRowAtIndexPath 中将 selectionStyle 设置为 UITableViewCellSelectionStyleNone。为什么?因为如果没有这种选择样式,则无法选择单元格,但在按下时仍会显示“选中状态”(因此,如果其他单元格有一个颜色,则它会更改为所选颜色)
    • 这应该比接受的答案有更多的赞成票
    • 我认为这不是被接受的答案的主要原因是因为被接受的答案更容易。虽然这不是“最好的方法”,因为您的表格仍会在您的单元格上调用 setSelected: ,但它在视觉上仍然有效。这里的这个答案需要更多的工作,但它是正确的方法(你必须结合@TooManyEduardos 的建议)以避免表格调用 setSelected: 在你的单元格上的任何不可预见的后果。
    • 我喜欢这个答案,但是如果您不想在 cellForRowAtIndexPath 和 willSelectRowAtIndexPath 中复制您的逻辑,只需检查 willSelectRowAtIndexPath 中的 cell.selectionStyle == none 是否返回 nil(请参阅下面的答案)
    【解决方案3】:

    从iOS 6开始,你可以使用

    -tableView:shouldHighlightRowAtIndexPath:
    

    如果您返回 NO,它将禁用选择突出显示和连接到该单元格的情节提要触发的 segues。

    当触摸一行时调用该方法。将NO 返回到该消息会停止选择过程,并且不会导致当前选定的行在触摸时失去其选定的外观。

    UITableViewDelegate Protocol Reference

    【讨论】:

    • 同意。对于 iOS 7 及更高版本,这应该是首选方法(事实上,在 iOS 8 上,其他方法对我不起作用。)
    • 这应该是最佳答案。
    【解决方案4】:

    以上答案都没有真正正确解决问题。原因是我们要禁用单元格的选择,但不一定要禁用单元格内的子视图。

    在我的例子中,我在行的中间展示了一个 UISwitch,我想禁用对行的其余部分(为空)的选择,但不是开关!因此,正确的做法是在方法中

    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    

    where语句的形式

    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
    

    禁用对特定单元格的选择,同时允许用户操作开关,从而使用适当的选择器。如果有人通过

    禁用用户交互,则不是这样
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    

    仅准备单元格且不允许与 UISwitch 交互的方法。

    另外,使用方法

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    

    为了取消选择带有表单语句的单元格

    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    

    当用户按下单元格的原始 contentView 时,仍然显示被选中的行。

    只有我的两分钱。我很确定很多人会觉得这很有用。

    【讨论】:

    • 同意。在willSelectRowAtIndexPath 中返回 nil 也有同样的问题,子视图不可选。
    • 另外请注意,如果您有一个静态表格,您可以在界面生成器中为您不希望出现选择的单元格将选择设置为无。
    【解决方案5】:

    Swift 4.0 为例:

    cell.isUserInteractionEnabled = false
    cell.contentView.alpha = 0.5
    

    【讨论】:

      【解决方案6】:

      您可以使用这些数据源方法捕获选择。

      – tableView:willSelectRowAtIndexPath: 
      – tableView:didSelectRowAtIndexPath: 
      – tableView:willDeselectRowAtIndexPath: 
      – tableView:didDeselectRowAtIndexPath:
      

      在这些方法中,您检查所选行是否是您希望可选择的行。如果是,就采取行动,如果不是,什么也不做。

      很遗憾,您不能只关闭一个部分的选择。这是整张桌子或什么都没有。

      但是,您可以将表格单元格的selectionStyle 属性设置为UITableViewCellSelectionStyleNone。我相信这将使选择不可见。结合上述方法,从用户的角度来看,应该使细胞看起来完全惰性。

      编辑01:

      如果您的表格中只有部分行是可选择的,那么可选择行的单元格在视觉上与不可选择的行不同是很重要的。 V 形附件按钮是执行此操作的默认方式。

      无论如何,您都不希望您的用户尝试选择行并认为应用程序有问题,因为该行没有做任何事情。

      【讨论】:

      • 请详细说明如何使用这些方法或给出一些示例程序链接
      • @Warrior:如果你已经安装了 SDK,你可以打开 Xcode,转到Help -&gt; Developer documentation,然后将这些方法名称复制到搜索字段中,看看它是如何工作的。开发者文档还包含示例代码。
      【解决方案7】:

      您需要执行以下操作来禁用cellForRowAtIndexPath 方法中的单元格选择:

      [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
      [cell setUserInteractionEnabled:NO];
      

      要将单元格显示为灰色,请将以下内容放入 tableView:WillDisplayCell:forRowAtIndexPath 方法中:

      [cell setAlpha:0.5];
      

      一种方法允许您控制交互性,另一种方法允许您控制 UI 外观。

      【讨论】:

        【解决方案8】:

        对于快速:

        cell.selectionStyle = .None
        cell.userInteractionEnabled = false
        

        【讨论】:

        • 这对我来说是最好的解决方案,除了我离开 isUserInteractiveEnabled。我用不同的控件以编程方式创建了许多可重用的单元格,即带有 UISwitch、UISlider、UIPickerView 等的单元格。单元格本身不能被触摸,并且附件控件保持用户交互。无需在委托中继续重新实现。
        【解决方案9】:

        要停止选择某些单元格,请使用:

        cell.userInteractionEnabled = NO;
        

        除了阻止选择之外,这还会停止为设置它的单元格调用 tableView:didSelectRowAtIndexPath:。

        【讨论】:

        • 一件奇怪的事情总是发生:当我在一个单元格上将userInteractionEnabled 设置为 NO(更清楚地说,一个 indexPath)时,某些其他单元格的用户交互被禁用。我不知道为什么每次我在表格视图单元格上使用userInteractionEnabled 时都会发生这种情况。是已知的错误还是我做错了什么?
        • @Philip007 “否”单元格是否被重复使用?如果是这样,您可能需要确保在出列单元格时将其设置为“YES”。
        • 为什么设置为“YES”?我希望它为 NO(禁止用户交互)。一个典型的例子是我在使单元格出列后将tableView:cellForRowAtIndexPath: 中的第一行(if [indexPath row] == 0)的用户交互设置为NO。一开始通常可以正常工作。然后在reloadData的几次调用之后,突然第五行不允许交互,然后第四行..我不知道什么时候会发生。整个事情看起来很随意。
        • @Philip007 如果您要重复使用单元格,您需要将其重置为“YES”,以便您希望 进行交互的单元格。否则,如果在您确实想要交互的行中重复使用“否”单元格,它仍将被禁用。即:if [indexPath row] == 0) { set to NO } else { set to YES }
        【解决方案10】:

        对于 Swift 4.0 这会成功的。 它将禁用 didSelectRowAtIndexPath 方法中的单元格,但保持子视图可点击。

        func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
                 if (indexPath.row == clickableIndex ) { 
                    return indexPath
                 }else{
                    return nil
                }
            }
        

        【讨论】:

        • 或者简称:return indexPath.row == clickableIndex ? indexPath : nil,让你的代码更简洁;-)
        【解决方案11】:

        您可以使用tableView:willDisplayCell 方法对tableViewCell 进行各种自定义。

        - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
        {
             [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
             [cell setUserInteractionEnabled:NO];
        
             if (indexPath.section == 1 && indexPath.row == 0)
             {
                 [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
                 [cell setUserInteractionEnabled:YES];
             }
        } 
        

        在上面这段代码中,用户只能选择tableView第二部分的第一行。其余所有行无法选择。谢谢!~

        【讨论】:

          【解决方案12】:

          我的基于数据模型的解决方案:

          func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
              let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
              return rowDetails.enabled ? indexPath : nil
          }
          
          func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
              let rowDetails = viewModel.rowDetails(forIndexPath: indexPath)
              return rowDetails.enabled
          }
          

          【讨论】:

            【解决方案13】:

            使用它使单元格看起来像它被禁用且不可选择:

            cell.selectionStyle = UITableViewCellSelectionStyleNone;
            

            重要提示:请注意,这只是一个样式属性,实际上并没有禁用单元格。为此,您必须在您的 didSelectRowAtIndexPath: 委托实现中检查 selectionStyle

            - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
                UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                if(cell.selectionStyle == UITableViewCellSelectionStyleNone) {
                    return;
                }
            
                // do your cell selection handling here
            }
            

            【讨论】:

              【解决方案14】:

              我喜欢上面的 Brian Chapados 回答。但是,这意味着您可能在 cellForRowAtIndexPath 和 willSelectRowAtIndexPath 中都有重复的逻辑,这很容易不同步。无需重复逻辑,只需检查 selectionStyle:

              - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
              {
                  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                  if (cell.selectionStyle == UITableViewCellSelectionStyleNone)
                      return nil;
              
                  else
                      return indexPath;
              }
              

              【讨论】:

                【解决方案15】:

                我发现这很方便,因为它适用于静态和动态表。我只在我希望允许选择的单元格上设置披露指示符。

                - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
                    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
                    if (cell.accessoryType != UITableViewCellAccessoryDisclosureIndicator) {
                        return nil;
                    }
                    return indexPath;
                }
                

                【讨论】:

                  【解决方案16】:

                  在没有编码的 Xcode 7 上,您可以简单地执行以下操作:

                  在大纲视图中,选择表格视图单元格。 (该单元格嵌套在 Table View Controller Scene > Table View Controller > Table View 下。您可能必须公开这些对象才能看到 table view 单元格)

                  在属性检查器中,找到标记为“选择”的字段并选择“无”。 atribute inspector 使用此选项,当用户点击单元格时,单元格将不会获得视觉突出显示。

                  【讨论】:

                    【解决方案17】:

                    appart from tableView.allowsMultipleSelection = true 您需要在选择时取消选择该部分的其余单元格:

                    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                        if indexPath.section does not support multiple selection {
                            // deselect the rest of cells
                            tableView
                                .indexPathsForSelectedRows?.compactMap { $0 }
                                .filter { $0.section == indexPath.section && $0.row != indexPath.row }
                                .forEach { tableView.deselectRow(at: $0, animated: true) }
                        }
                    }
                    

                    【讨论】:

                      【解决方案18】:

                      简单

                      如果单元格可以导航,请使用cell.userInteractionEnabled = YES;,否则使用cell.userInteractionEnabled = NO;

                      【讨论】:

                      • 这也防止了与单元格内的任何附件视图的交互,这可能不是所需的行为。
                      【解决方案19】:

                      只实现方法tableView:willSelectRowAtIndexPath: 在表的数据源中。如果要突出显示路径处的行,请返回给定的 indexPath。如果没有,则返回 nil。

                      我的应用示例:

                      - (NSIndexPath *)tableView:(UITableView *)tableView
                          willSelectRowAtIndexPath:(NSIndexPath *)indexPath
                      {
                          MySelectableObj* obj = [self objectAtPath:indexPath];
                          if(obj==nil) return nil;
                          return indexPath;
                      }
                      

                      这样做的好处是如果上面的方法返回 nil,shouldPerformSegueWithIdentifier:sender: 将不会被调用,尽管我重复上面的测试只是为了完整性。

                      【讨论】:

                        【解决方案20】:

                        对于 Xcode 6.3:

                         cell.selectionStyle = UITableViewCellSelectionStyle.None;
                        

                        【讨论】:

                          【解决方案21】:

                          我同意布莱恩的回答

                          如果我这样做

                          cell.isUserInteractionEnabled = false 
                          

                          那么单元格内的子视图将不会被用户交互。

                          在其他网站上,设置

                          cell.selectionStyle = .none
                          

                          尽管没有更新选择颜色,但仍会触发 didSelect 方法。

                          使用 willSelectRowAt 是我解决问题的方法。示例:

                          func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
                          
                              if indexPath.section == 0{
                          
                                  if indexPath.row == 0{
                                      return nil
                                  }
                          
                              }
                              else if indexPath.section == 1{
                          
                                  if indexPath.row == 0{
                                      return nil
                                  }
                          
                              }
                          
                              return indexPath
                          
                          }
                          

                          【讨论】:

                            【解决方案22】:

                            斯威夫特 5: 将以下行放在您的 cellForRowAt 函数中:

                            cell.selectionStyle = UITableViewCell.SelectionStyle.none
                            

                            【讨论】:

                              【解决方案23】:

                              对于 swift 3.0,您可以使用以下代码禁用用户与 UITableView 单元格的交互

                               cell.isUserInteractionEnabled = false
                              

                              【讨论】:

                                猜你喜欢
                                • 2016-05-31
                                • 1970-01-01
                                • 2021-12-17
                                • 1970-01-01
                                • 1970-01-01
                                • 2012-08-28
                                • 1970-01-01
                                • 2015-05-21
                                • 1970-01-01
                                相关资源
                                最近更新 更多