iphone中的可扩展tableView

时间:2012-07-24 07:25:41

标签: ios iphone xcode uitableview

enter image description here

我想制作这种可扩展/可折叠表格视图。 图中有类别和子类别。 例如,“健康和美丽”是一个类别,当我点击此单元格而不是其打开的子类别时,如下图所示。 那么我该如何制作这种类型的表格视图呢? 请建议我。

14 个答案:

答案 0 :(得分:17)

最后,我得到两个非常有用的帮助链接,下面详细描述了这里的要求 Expanding/Collapsing TableView Sections
Collapsable Table View for iOS

真的,这类扩展/折叠tableview部分的好文章

答案 1 :(得分:10)

将可扩展Cell的以下代码用于UITableView

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";   
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    cell.textLabel.text=[[self.arForTable objectAtIndex:indexPath.row] valueForKey:@"name"];
    [cell setIndentationLevel:[[[self.arForTable objectAtIndex:indexPath.row] valueForKey:@"level"] intValue]];    
    return cell;
}

扩展和扩展的代码折叠行 - TableView DidSelectRow方法

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    NSDictionary *d=[self.arForTable objectAtIndex:indexPath.row];
    if([d valueForKey:@"Objects"]) {
        NSArray *ar=[d valueForKey:@"Objects"];
        BOOL isAlreadyInserted=NO;
        for(NSDictionary *dInner in ar ){
            NSInteger index=[self.arForTable indexOfObjectIdenticalTo:dInner];
            isAlreadyInserted=(index>0 && index!=NSIntegerMax);
            if(isAlreadyInserted) break; 
        }
        if(isAlreadyInserted) {
            [self miniMizeThisRows:ar];
        } else {        
            NSUInteger count=indexPath.row+1;
            NSMutableArray *arCells=[NSMutableArray array];
            for(NSDictionary *dInner in ar ) {
                [arCells addObject:[NSIndexPath indexPathForRow:count inSection:0]];
                [self.arForTable insertObject:dInner atIndex:count++];
            }
            [tableView insertRowsAtIndexPaths:arCells withRowAnimation:UITableViewRowAnimationLeft];
        }
    }
}

一种有助于减少和减少的方法。最大化/展开 - 折叠行。

-(void)miniMizeThisRows:(NSArray*)ar{
    for(NSDictionary *dInner in ar ) {
        NSUInteger indexToRemove=[self.arForTable indexOfObjectIdenticalTo:dInner];        
        NSArray *arInner=[dInner valueForKey:@"Objects"];
        if(arInner && [arInner count]>0){
            [self miniMizeThisRows:arInner];
        }
        if([self.arForTable indexOfObjectIdenticalTo:dInner]!=NSNotFound) {
            [self.arForTable removeObjectIdenticalTo:dInner];
            [self.tableView deleteRowsAtIndexPaths:
              [NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexToRemove inSection:0]]
                      withRowAnimation:UITableViewRowAnimationRight];
        }
    }
}

You can download source code from here.

答案 2 :(得分:8)

如果这有帮助:[访问uitableview可展开和可折叠部分] https://github.com/OliverLetterer/UIExpandableTableView

答案 3 :(得分:6)

我对可扩展表视图有一些不同的方法 - 一种与通常构建这些类表视图的方式一致。

标题单元格标题 tappable ,然后标题下方的单元格显示或隐藏。这可以通过向标题添加手势识别器来实现,当点击时,您只需删除该标题下的所有单元格(该部分),反之亦然(添加单元格)。当然,您必须保持哪些标题是“打开”的状态以及哪些标题是“已关闭”。

这很好,有几个原因:

  1. 标题和单元格的工作是分开的,这使代码更清晰。
  2. 这个方法可以很好地构建表视图的方式(标题和单元格),因此没有太大的魔力 - 代码只是删除或添加单元格,并且应该与更高版本的iOS兼容。
  3. 我创建了一个非常简单的库来实现这一目标。只要您的表视图设置了UITableView节标题和单元格,您所要做的就是将tableview和标题子类化。试试吧:))

    链接:https://github.com/fuzz-productions/FZAccordionTableView

    enter image description here

答案 4 :(得分:5)

尝试使用此代码...可能这可以帮助.. 并随意根据您的要求编辑代码...

#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
@interface ViewController ()

@end

@implementation ViewController
@synthesize myTable;
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    //myTable.backgroundColor=[UIColor clearColor];
   // self.view.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"wood.png"]];
    muArr= [[NSMutableArray alloc]initWithObjects:@"Vinay",@"Anmol",@"Jagriti", nil];
    ExpArr=[[NSMutableArray alloc]initWithObjects:@"Useeee",@"Thissss",@"Codeee", nil];
    otherExpand=100;
    checker=100;

}

-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
    return muArr.count;
}

-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if(otherExpand==section)
    return ExpArr.count;

    return  0;

}

-(BOOL)tableView:(UITableView *)table canCollapse:(NSIndexPath *)indexPath
{

    return NO;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *Identifier=@"Cell";
    UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:Identifier];
    if (cell==nil)
    {
        cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Identifier];

    }
    cell.textLabel.text=[ExpArr objectAtIndex:indexPath.row];
    cell.textLabel.backgroundColor=[UIColor clearColor];
    UIView *viewww=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
    viewww.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"wood.png"]];
    cell.backgroundView=viewww;

   // cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"wood.png"]];
    [tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLineEtched];
    [tableView setSeparatorColor:[UIColor purpleColor]];

    return cell;

}

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{

    UIView *view1=[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
    [view1.layer setCornerRadius:20];
    view1.layer.borderWidth=2;
    view1.layer.borderColor=[UIColor brownColor].CGColor;
    UILabel *label=[[UILabel alloc]initWithFrame:CGRectMake(10, 0, 295, 44)];
    label.backgroundColor=[UIColor clearColor];

    label.text=[muArr objectAtIndex:section];
    UIButton *btn=[UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    btn.frame=CGRectMake(280, -5, 50, 50);
    btn.backgroundColor=[UIColor clearColor];
    btn.tag=section;

    view1.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"wood.png"]];
    label.textColor=[UIColor blackColor];
    label.font=[UIFont fontWithName:@"American TypeWriter" size:18];
    //btn.backgroundColor=[UIColor blackColor];
    [view1 addSubview:btn];
    [view1 addSubview:label];

    [btn addTarget:self action:@selector(Btntap:) forControlEvents:UIControlEventTouchUpInside];

    return view1;
}


-(void)Btntap : (UIButton *)btn
{
    if(otherExpand!=100)
    {
        if (otherExpand==btn.tag)
        {
            NSMutableArray *tempArr2=[[NSMutableArray alloc]init];
            for(int j=0;j<ExpArr.count;j++)
            {
                NSIndexPath *indexx1=[NSIndexPath indexPathForRow:j inSection:otherExpand];
                [tempArr2 addObject:indexx1];
            }
            checker=0;
            otherExpand=100;
            [myTable deleteRowsAtIndexPaths:tempArr2 withRowAnimation:UITableViewRowAnimationAutomatic];
        }

        else
        {
            NSMutableArray *tempArr2=[[NSMutableArray alloc]init];
            for(int j=0;j<ExpArr.count;j++)
            {
                NSIndexPath *indexx1=[NSIndexPath indexPathForRow:j inSection:otherExpand];
                [tempArr2 addObject:indexx1];
            }
            checker=1;
            otherExpand=100;
            [myTable deleteRowsAtIndexPaths:tempArr2 withRowAnimation:UITableViewRowAnimationAutomatic];
        }
    }

    if(checker!=0)
    {
        otherExpand=btn.tag;
        //checker=
        NSMutableArray *tempArr=[[NSMutableArray alloc]init];
        for(int i=0;i<ExpArr.count;i++)
        {
            NSIndexPath *indexx=[NSIndexPath indexPathForRow:i inSection:btn.tag];
            [tempArr addObject:indexx];
        }
        [myTable insertRowsAtIndexPaths:tempArr withRowAnimation:UITableViewRowAnimationAutomatic];

        checker=1;
    }
    checker=100;
}



-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 44;
}

@end

答案 5 :(得分:4)

WWDC 2011中有一个名为UITableView Changes, Tips and Tricks - session 125的精彩视频,展示了如何做这样的事情 另请查看示例代码TVAnimationsGestures

答案 6 :(得分:3)

您可以在Swift中查看这个手风琴示例:https://github.com/tadija/AEAccordion

enter image description here

创建手风琴效果的代码非常少(不是通过使用部分而是单元格),作为奖励,还有一种在其他XIB文件中使用XIB文件的解决方案(对于使用自定义的自定义单元格非常有用)视图)。

答案 7 :(得分:2)

请尝试这个例子:

可扩展TableView的最佳示例

https://github.com/OliverLetterer/UIExpandableTableView

答案 8 :(得分:1)

TLIndexPathTools可以自然地做这件事。事实上,可扩展部分和可扩展树结构都有扩展。尝试为可扩展部分运行Collapse示例项目,为可扩展树运行Outline sample project

使用TLIndexPathTools的一个优点是,作为一个简单的低级API,它可以使用通用方法解决各种动态表视图和集合视图问题。它可以与Core Data和普通数组互换使用。

答案 9 :(得分:1)

创建可扩展的tableview是如此容易 这是我如何做到这一点的示例,

我为此使用的数据

struct ItemList {
var name: String
var items: [String]
var collapsed: Bool

init(name: String, items: [String], collapsed: Bool = false) {
   self.name = name
   self.items = items
   self.collapsed = collapsed
   }
}

var sections = [ItemList]()

var items: [ItemList] = [
 ItemList(name: "Mac", items: ["MacBook", "MacBook Air"]),
 ItemList(name: "iPad", items: ["iPad Pro", "iPad Air 2"]),
 ItemList(name: "iPhone", items: ["iPhone 7", "iPhone 6"])
]

现在只需添加这段代码并相应地使用

extension ViewController:UITableViewDelegate,UITableViewDataSource{

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 60
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerHeading = UILabel(frame: CGRect(x: 5, y: 10, width: self.view.frame.width, height: 40))
    let imageView = UIImageView(frame: CGRect(x: self.view.frame.width - 30, y: 20, width: 20, height: 20))
    if items[section].collapsed{
        imageView.image = UIImage(named: "collapsed")
    }else{
        imageView.image = UIImage(named: "expand")
    }
    let headerView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 60))
    let tapGuesture = UITapGestureRecognizer(target: self, action: #selector(headerViewTapped))
    tapGuesture.numberOfTapsRequired = 1
    headerView.addGestureRecognizer(tapGuesture)
    headerView.backgroundColor = UIColor.red
    headerView.tag = section
    headerHeading.text = items[section].name
    headerHeading.textColor = .white
    headerView.addSubview(headerHeading)
    headerView.addSubview(imageView)
    return headerView
 }
func numberOfSections(in tableView: UITableView) -> Int {
    return items.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    let itms = items[section]
    return !itms.collapsed ? 0 : itms.items.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! UITableViewCell
    cell.textLabel?.text = items[indexPath.section].items[indexPath.row]
    return cell
}
@objc func headerViewTapped(tapped:UITapGestureRecognizer){
    print(tapped.view?.tag)
    if items[tapped.view!.tag].collapsed == true{
        items[tapped.view!.tag].collapsed = false
    }else{
        items[tapped.view!.tag].collapsed = true
    }
    if let imView = tapped.view?.subviews[1] as? UIImageView{
        if imView.isKind(of: UIImageView.self){
            if items[tapped.view!.tag].collapsed{
                imView.image = UIImage(named: "collapsed")
            }else{
                imView.image = UIImage(named: "expand")
            }
        }
    }
    tableView.reloadData()
}

}

结果是宾果游戏:)

enter image description here

答案 10 :(得分:0)

检查此链接:

http://iostechnotips.blogspot.in/2014/05/expandable-uitableview.html

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

*使用UITableView委托方法viewForHeaderInSection并返回自定义UIView。

*添加UIButton作为子视图,其中包含操作&#34; expandable:(id)sender&#34;将发件人ID检查为部分编号并重新加载表视图。

答案 11 :(得分:0)

在你的.h文件中

LoadCustomCell *cell1;
NSMutableArray  *arrayForBool;
NSMutableArray  *questionArray;
NSMutableArray  *answerArray;

在你的.m文件中

 viewDidLoadMethod {
 _faqTblView.estimatedRowHeight = 30;
 _faqTblView.rowHeight = UITableViewAutomaticDimension;
 arrayForBool = [[NSMutableArray alloc]init];

 _questionArray = [[NSMutableArray alloc]init];
 _answerArray = [[NSMutableArray alloc]init];
 for (int i = 0; i < _questionArray.count; i++) {
        [arrayForBool addObject:@"0"];
    }
    self.faqTblView.dataSource = self;
    self.faqTblView .delegate = self;
    [self.faqTblView reloadData];
 }

之后

 #pragma mark - TableView Datasource & Delegate Method.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
  return [_questionArray count];
 }
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {

    UILabel *lblText = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 260, 100)];
    lblText.text = [_questionArray objectAtIndex:section];
    return [lblText getLabelHeight] + 20;(created custom class)
 }
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

UITapGestureRecognizer  *headerTapped   = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
cell1 = [[[NSBundle mainBundle] loadNibNamed:@"LoadCustomCell" owner:self options:nil] objectAtIndex:0];
[cell1 setFrame:CGRectMake(0, 0, cell1.frame.size.width, cell1.frame.size.height)];
NSString *numStr = [NSString stringWithFormat:@"%ld. ",section + 1];
[cell1.sideMenuUserNameLabel setText:[numStr stringByAppendingString:[_questionArray objectAtIndex:section]]];
[cell1 setBackgroundColor:[UIColor lightGrayColor]];
cell1.tag = section;
[cell1 addGestureRecognizer:headerTapped];

return cell1;
}

- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer {

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:gestureRecognizer.view.tag];
if (indexPath.row == 0) {
    BOOL collapsed  = [[arrayForBool objectAtIndex:indexPath.section] boolValue];
    for (int i = 0; i < [_questionArray count]; i++) {
        if (indexPath.section==i) {
            [arrayForBool removeObjectAtIndex:i];
            [arrayForBool insertObject:[NSString stringWithFormat:@"%d", !collapsed] atIndex:i];
        }
    }
    NSLog(@"%@", arrayForBool);
    [self.faqTblView reloadSections:[NSIndexSet indexSetWithIndex:gestureRecognizer.view.tag] withRowAnimation:UITableViewRowAnimationAutomatic];
    for (NSIndexPath *indexPath in self.faqTblView.indexPathsForSelectedRows) {
        [self.faqTblView deselectRowAtIndexPath:indexPath animated:NO];
         }
    cell1.imageView.transform = CGAffineTransformMakeRotation(M_PI);
     }
}

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *questionCellIdentifier = @"questionCellIdentifier";
QuestionCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:questionCellIdentifier];
if (cell == nil) {
    NSArray * myNib;
    myNib =[[NSBundle mainBundle]loadNibNamed:@"QuestionCustomCell" owner:self options:nil];
    cell = (QuestionCustomCell *)[myNib lastObject];
}

BOOL manyCells  = [[arrayForBool objectAtIndex:indexPath.section] boolValue];
if(manyCells){
    cell.questionNameLbl.text = [_answerArray objectAtIndex:indexPath.section];
}
return cell;
}

答案 12 :(得分:0)

您可以使用ExpyTableView

从您的给定单元格中生成可扩展部分。兼容iOS 8.0。通过生成具有多个表视图单元的可扩展表视图,您将具有灵活性。只需操作状态分隔符,然后就不会有人知道你正在使用多个单元格进行扩展。

  • 其他解决方案:您操纵高度以扩展单元格,当单元格设计需要更新时,您必须重新构建所有自动布局约束或逻辑码。

  • ExpyTableView:通过使用多个单元格并插入和删除它们(这可能意味着扩展和折叠),您可以创建可扩展的表格视图,您将在未来的设计请求中获得很大的机会。您所要做的就是添加一个新的UITableViewCell并为其编写代码。您将轻松拥有新设计。

您所要做的就是import ExpyTableView然后:

class ViewController: ExpyTableViewDataSource, ExpyTableViewDelegate {

  @IBOutlet weak var expandableTableView: ExpyTableView!

  // First, set data source and delegate for your table view.
  override func viewDidLoad() {
    super.viewDidLoad() 
    expandableTableView.dataSource = self
    expandableTableView.delegate = self
  }

  // Then return your expandable cell instance from expandingCell data source method.
  func expandableCell(forSection section: Int, inTableView tableView: ExpyTableView) -> UITableViewCell {
    // this cell will be displayed at IndexPath with section: section and row 0
  }
} 

您可以看到以前的表格视图部分现在是一个可展开的表格视图部分。您也可以下载example project并查看更详细的示例。

答案 13 :(得分:0)

我需要将单个单元格展开为更完整的视图,然后将其折叠回汇总视图。

所以我所做的是使用 UIStackView 设计我的单元格。我将不想在折叠状态下显示的视图隐藏起来,然后在点击单元格时显示它。

这里的技巧是在 tableView.beginUpdates()tableView.endUpdates() 语句中显示和隐藏视图。通过这种方式,表格视图会自动调整单元格高度并进行动画处理。

以下是基本单元格在 IB 中的外观: enter image description here

单元格自定义类:

    class AccordionCell: UITableViewCell {
    @IBOutlet weak var stackView: UIStackView!
    
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var extendedDescriptionLabel: UILabel!

    var expanded: Bool = false {
        didSet {
            if let extended = self.extendedDescriptionLabel {
                extended.isHidden = !expanded
            }
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        self.expanded = false
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }    
}

UITableView 委托实现:

extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as! AccordionCell
        cell.titleLabel.text = "Row: \(indexPath.row)"
        cell.expanded = indexPath.row == expanded
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) as? AccordionCell {
            tableView.beginUpdates()
            if expanded == indexPath.row {
                cell.expanded = false
                expanded = -1
            }
            else {
                cell.expanded = true
                expanded = indexPath.row
            }
            
            tableView.endUpdates()
            tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
        }
    }
    
    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) as? AccordionCell {
            tableView.beginUpdates()
            cell.expanded = false
            tableView.endUpdates()
        }
    }
}

为了跟踪哪个单元格被展开,我引入了一个变量来保存当前展开的单元格的 indexpath 以便在滚动 tableview 时展开正确的单元格。