具有行展开和折叠选项的表格视图的最佳方法

Posted

技术标签:

【中文标题】具有行展开和折叠选项的表格视图的最佳方法【英文标题】:best approach for tableview with rows expand and collapse option 【发布时间】:2016-10-20 10:59:24 【问题描述】:

我有包含表格视图和搜索栏的视图。当我开始搜索时,它应该搜索 tableview。下面是附图中tableview的示例数据:

STUDENT 1、STUDENT 2 是表中的不同部分

假设我搜索“S”,那么结果应该如下所示,其中匹配的行应该是可见的,不匹配的行应该被隐藏,并且“显示剩余”按钮应该是可见的。当我点击“显示剩余”按钮时,它应该显示同一部分的剩余行:

我如何实现这一点,如果可能,请提供上述场景的示例。

【问题讨论】:

几个问题,以更好地了解您的需求。 1. STUDENT 部分没有任何行与搜索匹配,会发生什么情况? 2.“显示剩余”按钮是每个部分只影响一个部分还是所有部分都在按钮上? @ Sergii Martynenko Jr - 每个部分都有“显示剩余”按钮。如果部分中没有匹配项,则该部分被隐藏或删除。 很好,如果您向我们提供反馈,任何答案对您有帮助吗? @Sergii Martynenko J,Ramkrishna Sharma,Hasya - 非常感谢你们的及时帮助。 【参考方案1】:

我已经为您的要求创建了代码,请找到下面的 url 下载代码并查看它。

链接:https://www.dropbox.com/s/22ijwgxybn98wyj/ExpandCollapse.zip?dl=0

环境:Xcode 8 和 Objective-C

突出显示我编写的代码。

我已经根据你的结构创建了student的NSObject,创建了两个(StudentListCell和ShowMoreCell)UITableViewCell用于显示student的记录和“Show Remaining button”记录。

我还拿了两个(arrStudentInfo, arrSearchInfo) NSMutablebleArray 来保存搜索记录和原始记录。

之后我在ViewController.m 中初始化student 的NSObject。请找到以下代码。

- (void)setupData 

    self.arrStudentInfo = [[NSMutableArray alloc] init];
    self.arrSearchInfo = [[NSMutableArray alloc] init];

    StudentInfo *student_1 = [[StudentInfo alloc] init];
    student_1.name = @"Sia S";
    student_1.style = @"S";
    student_1.trend = @"S";
    student_1.age = @"60";
    student_1.locale = @"Node";
    student_1.street = @"BR";
    student_1.city = @"JP";
    student_1.country = @"US";
    student_1.isOpen = YES;
    student_1.isShowMore = NO;
    [self.arrStudentInfo addObject:student_1];

    StudentInfo *student_2 = [[StudentInfo alloc] init];
    student_2.name = @"Nitin";
    student_2.style = @"N";
    student_2.trend = @"N";
    student_2.age = @"40";
    student_2.locale = @"Node";
    student_2.street = @"BR";
    student_2.city = @"SP";
    student_2.country = @"US";
    student_2.isOpen = YES;
    student_2.isShowMore = NO;
    [self.arrStudentInfo addObject:student_2];

我已经创建了返回当前活动的方法,这意味着搜索记录或数组的原始记录。

- (NSMutableArray *)getCurrentArray 

    if(self.isSearch)
        return self.arrSearchInfo;
    else
        return self.arrStudentInfo;

根据场景加载数据,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    StudentInfo *studentInfo = [self getCurrentArray][indexPath.section];

    if(indexPath.row == SHOW_MORE_INDEX && studentInfo.isShowMore == NO) 

        static NSString *strCellIdentifier = @"ShowMoreCell";
        ShowMoreCell *cell = [tableView dequeueReusableCellWithIdentifier:strCellIdentifier];
        cell.btnShowMore.tag = indexPath.section;
        [cell.btnShowMore addTarget:self action:@selector(clickONShowMore:) forControlEvents:UIControlEventTouchUpInside];

        return cell;
    

    else 

        static NSString *strCellIdentifier = @"StudentListCell";

        StudentListCell *cell = [tableView dequeueReusableCellWithIdentifier:strCellIdentifier];
        [cell setupCell:studentInfo indexPath:indexPath];

        return cell;
    

用于搜索学生姓名,

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar 

    [searchBar resignFirstResponder];
    self.isSearch = YES;

    NSPredicate *predicateStudent = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"self.name CONTAINS[cd] '%@'",searchBar.text]];
    NSArray *arrGetSearch = [self.arrStudentInfo filteredArrayUsingPredicate:predicateStudent];

    if(self.arrSearchInfo.count)
        [self.arrSearchInfo removeAllObjects];

    [self.arrSearchInfo addObjectsFromArray:arrGetSearch];
    [self.tblView reloadData];

如果用户单击UISearchbar 上的“X”按钮,则再次加载原始记录。

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 

    if([searchText isEqualToString:@""] || searchText==nil) 

        [searchBar resignFirstResponder];
        self.isSearch = NO;
        [self.tblView reloadData];
    

希望这对你有用。

【讨论】:

实际上,从某种意义上说,这并不是最好的方法。例如,您已将属性“isShowMore”放入模型类 Student 中,这是不好的做法。 “显示全部”选项与Model无关,是Student类。 感谢您的评论,实际上我已经在模型中使用了 isShowMore 标志来识别每条记录是否允许显示更多。请让我知道我是否必须放置它。【参考方案2】:

有很多可用于展开和折叠表格的示例。

你可以参考下面的例子

http://www.appcoda.com/expandable-table-view/

通过在 plist 文件中动态设置。您可以维护可扩展和可折叠的表格视图。

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath)
    let cell = tableView.dequeueReusableCellWithIdentifier(currentCellDescriptor["cellIdentifier"] as! String, forIndexPath: indexPath) as! CustomCell

    if currentCellDescriptor["cellIdentifier"] as! String == "idCellNormal" 
        if let primaryTitle = currentCellDescriptor["primaryTitle"] 
            cell.textLabel?.text = primaryTitle as? String
        

        if let secondaryTitle = currentCellDescriptor["secondaryTitle"] 
            cell.detailTextLabel?.text = secondaryTitle as? String
        
    
    else if currentCellDescriptor["cellIdentifier"] as! String == "idCellTextfield" 
        cell.textField.placeholder = currentCellDescriptor["primaryTitle"] as? String
    
    else if currentCellDescriptor["cellIdentifier"] as! String == "idCellSwitch" 
        cell.lblSwitchLabel.text = currentCellDescriptor["primaryTitle"] as? String

        let value = currentCellDescriptor["value"] as? String
        cell.swMaritalStatus.on = (value == "true") ? true : false
    
    else if currentCellDescriptor["cellIdentifier"] as! String == "idCellValuePicker" 
        cell.textLabel?.text = currentCellDescriptor["primaryTitle"] as? String
    
    else if currentCellDescriptor["cellIdentifier"] as! String == "idCellSlider" 
        let value = currentCellDescriptor["value"] as! String
        cell.slExperienceLevel.value = (value as NSString).floatValue
    

    return cell

【讨论】:

【参考方案3】:

对于 UITableView 中的折叠/展开行为,我想不出任何通用的“最佳方法”。我怀疑这就是Apple没有提供的原因。相反,他们给了我们足够的工具来按照我们希望的方式实施它。

在你的特殊情况下,我有下一个愿景。 我不知道,也不需要知道,您究竟是如何处理任务的模型方面的,以下代码仅用于此答案的目的,即 - 为您提供您所寻求的折叠行为。

我建议以这种方式实现您想要的行为。在 ViewController 中,您可以在其中控制搜索栏和表格视图添加字段

@property NSArray* filteredStudents;
@property NSMutableIndexSet* expandedStudents;

当没有进行搜索时,这些属性将为 nil(或空实例)。一旦搜索开始(输入第一个符号或点击“搜索”按钮 - 无论你最喜欢什么) - 实例化它们。

filteredStudents - 包含对那些满足您搜索条件的学生的引用的数组。每次执行搜索时都会更新。每次更新时 - 执行 [tableView reloadData]。

expandedStudents - 索引集,告诉您用户在哪些部分按下了“显示全部”。不要忘记 - 它只包含部分编号。因此,当filteredStudents 数组更改时,您必须手动更新它。例如,当您输入“S”时,您会看到两个学生。您对第二个学生按“全部显示”。 expandStudents 现在有编号 1。比你输入“Se”,只剩下第二个学生。在这种情况下,您必须将expandedStudents 中的1 替换为0,因为第二个学生的部分成为第一。

另一个属性

 @property BOOL searchMode;

每当过滤结果显示发生时,此属性都应为 YES。否 - 否则。

接下来,像这样修改 UITableViewDataSource 和 Delegate 方法

- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView 
    if(searchMode) 
       return self.filteredStudents.count;
    
    else 
       //Your current behaviour here
    


- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    if(searchMode) 
       if([self.expandedStudents containsIndex:section])  // Button "Show all" was already tapped for this student
          return /* Number of all fields you need to show for student. Just like you do now. It is for expanded section */
       
       else 
           return /* Number of fields that satisfy search criteria for student self.filteredStudents[section] */
       
    
    else 
       //Your current behaviour here
    


- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    if(searchMode) 
        if(![self.expandedStudents containsIndex:section] && /* indexPath corresponds to place, where "Show All" should be */) 
           //Create "Show All" cell
        
        else 
          //Create cell that contains info from filtered student fields
        
    
    else 
       //Your current behaviour here
    


- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath  
   if(searchMode && ![self.expandedStudents containsIndex:section] && /* indexPath corresponds to place, where "Show All" should be */) 
      //"Show All" button pressed
      [self.expandedStudents addIndex:indexPath.section];

      [tableView beginUpdates];
      /* For each row, that wasn't presented in collapsed student perform insertRowsAtIndexPaths:withRowAnimation: method */
      [tableView endUpdates];
   
   else 
      //Your current behaviour
   

【讨论】:

以上是关于具有行展开和折叠选项的表格视图的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使用展开和折叠数据行的选项将页脚模板添加到 gridview?C#/ASP.NET

在 UITableViewCell 中选择后展开和折叠特定行

展开和折叠表格视图单元格

具有可折叠选项的自动分隔器列表视图

展开和折叠表格视图中的单元格

如何以编程方式关闭展开的表格视图单元格?