iOS之仿QQ好友列表展开收缩效果的实现

使用 UICollectionView 实现

① 思路

  • 很明显整体它是一个列表,它的分组是一个列表,它里面的好友列表也是一个列表,所以就可以使用组头来设置分组列表,使用 cell 设置好友列表;
  • 当点击组头的时候会展开好友列表,其实原理上就是单独刷新某一组的数据。

② 流程

  • 控制器的代码(HomeViewController):本类主要配置 UICollectionView 显示,以及处理组展开/关闭状态。
#import "HomeViewController.h"
#import "YDWFriendListShowCollectionViewCell.h"
#import "YDWFriendHeaderReusableView.h"

static NSString * const kYDWFriendListShowCollectionViewCellIndentifier = @"YDWFriendListShowCollectionViewCell";
static NSString * const kYDWFriendHeaderReusableViewIndentifier = @"YDWFriendHeaderReusableView";

@interface HomeViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,FriendHeaderReusableViewDelegate>

/**
 添加collectionView
 */
@property(nonatomic,strong) UICollectionView *collectionView;
/**
 好友组头列表数组
 */
@property(nonatomic,strong) NSArray *headerArray;
/**
 好友列表数据
 */
@property (nonatomic, strong) NSMutableArray * dataArray;
/**
 存储是否展开的BOOL值
 */
@property (nonatomic, strong) NSMutableArray * boolArray;

@end

@implementation HomeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupNavigation];
    [self addSubviews];
    [self getListData];
}

#pragma mark - UICollectionViewDelegate,UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return self.headerArray.count;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    // 判断是否展开,如果未展开则返回0
    if ([self.boolArray[section] boolValue] == NO) {
        return 0;
    } else {
        return [self.dataArray[section] count];
    }
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    YDWFriendListShowCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kYDWFriendListShowCollectionViewCellIndentifier forIndexPath:indexPath];
    cell.contentView.backgroundColor = [UIColor whiteColor];
    cell.nameLabel.text = [NSString stringWithFormat:@"好友%ld", (long)indexPath.item];
    cell.detailsLabel.text = [NSString stringWithFormat:@"签名%ld", (long)indexPath.item];
    return cell;
}

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    YDWFriendHeaderReusableView *reusView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kYDWFriendHeaderReusableViewIndentifier forIndexPath:indexPath];
    reusView.delegte = self;
    reusView.backgroundColor = [UIColor whiteColor];
    reusView.tag = indexPath.section;
    
    // 三目运算选择展开或者闭合时候的图标
    reusView.imageView.image = [self.boolArray[indexPath.section] boolValue] ? [UIImage imageNamed:[NSString stringWithFormat:@"zhankai"]] : [UIImage imageNamed:[NSString stringWithFormat:@"shouqi"]];
    
    reusView.titleLabel.text = self.headerArray[indexPath.section];
    reusView.numLabel.text = [NSString stringWithFormat:@"%ld/%lu",(long)indexPath.section, (unsigned long)[self.dataArray[indexPath.section] count]];
    
    return reusView;
}

#pragma mark - FriendHeaderReusableViewDelegate
- (void)friendHeaderReusableView:(YDWFriendHeaderReusableView *)friendHeaderReusableView didSelectItemAtSection:(NSInteger)section {
   if ([self.boolArray[section] boolValue] == YES) {
       [self.boolArray replaceObjectAtIndex:section withObject:@NO];
   } else {
       [self.boolArray replaceObjectAtIndex:section withObject:@YES];
   }
   [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:section]];
}

#pragma mark - Private Methods
- (void)setupNavigation {
    self.navigationItem.title = @"联系人";
}

- (void)addSubviews {
    self.collectionView.frame = CGRectMake(0, 100, SCREEN_WIDTH, SCREEN_HEIGHT - 15);
    [self.view addSubview:self.collectionView];
}

- (void)getListData {
    // 准备组头的数据
    NSArray *headerArr = [NSArray arrayWithObjects:@"特别关心", @"我的好友", @"朋友", @"家人",nil];
    self.headerArray = headerArr;
    
    // 准备单元格的数据
    NSArray *itemArr = [NSArray arrayWithObjects:@5, @10, @7,@3,  nil];
    for (int i = 0; i < self.headerArray.count; i++) {
        // 所有的分组默认关闭
        [self.boolArray addObject:@NO];
        
        // 给每个分组添加数据
        NSMutableArray * friendArr = [[NSMutableArray alloc] init];
        for (int j = 0; j < [itemArr[i] intValue]; j++) {
            [friendArr addObject:@(j)];
        }
        [self.dataArray addObject:friendArr];
        
    }
    [self.collectionView reloadData];
}

#pragma mark - Lazy Loading
- (NSMutableArray *)dataArray {
    if (!_dataArray) {
        _dataArray = [[NSMutableArray alloc] init];
    }
    return _dataArray;
}

- (NSMutableArray *)boolArray {
    if (!_boolArray) {
        _boolArray = [[NSMutableArray alloc] init];
    }
    return _boolArray;
}

- (UICollectionView *)collectionView {
    if (!_collectionView) {
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        layout.itemSize = CGSizeMake(SCREEN_WIDTH, 70);
        layout.minimumLineSpacing = 0;
        layout.minimumInteritemSpacing = 0;
        layout.scrollDirection = UICollectionViewScrollDirectionVertical;
        layout.headerReferenceSize = CGSizeMake(SCREEN_WIDTH, 40);
        
        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
        _collectionView.backgroundColor = [UIColor whiteColor];
        _collectionView.delegate = self;
        _collectionView.dataSource = self;
        _collectionView.alwaysBounceVertical = YES;
        _collectionView.showsVerticalScrollIndicator = YES;
        
        [_collectionView registerClass:[YDWFriendHeaderReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kYDWFriendHeaderReusableViewIndentifier];
        [_collectionView registerClass:[YDWFriendListShowCollectionViewCell class] forCellWithReuseIdentifier:kYDWFriendListShowCollectionViewCellIndentifier];
    }
    return _collectionView;
}
@end
  • YDWFriendHeaderReusableView:本类主要布局组标题以及指示(展开/关闭)控件,其次,通过添加点击手势结合委托模式,传递 tag 值。
    YDWFriendHeaderReusableView.h 和 YDWFriendHeaderReusableView.m:
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN
@class YDWFriendHeaderReusableView;
@protocol FriendHeaderReusableViewDelegate <NSObject>

- (void)friendHeaderReusableView:(YDWFriendHeaderReusableView *)friendHeaderReusableView didSelectItemAtSection:(NSInteger)section;

@end

@interface YDWFriendHeaderReusableView : UICollectionReusableView

@property(nonatomic,weak) id <FriendHeaderReusableViewDelegate>delegte;

/**
 图标
 */
@property(nonatomic,weak) UIImageView *imageView;
/**
 标题
 */
@property(nonatomic,weak) UILabel *titleLabel;
/**
 人数
 */
@property(nonatomic,weak) UILabel *numLabel;
@end

NS_ASSUME_NONNULL_END

#import "YDWFriendHeaderReusableView.h"

@interface YDWFriendHeaderReusableView ()

@end

@implementation YDWFriendHeaderReusableView

#pragma mark - 初始化
- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.userInteractionEnabled = YES;
        UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickView:)];
        [self addGestureRecognizer:tapGes];
        
        [self addSubviews];
    }
    return self;
}

#pragma mark - 设置UI界面
- (void)addSubviews {
    // 添加图标
    UIImageView *imageView = [[UIImageView alloc] init];
    [self addSubview:imageView];
    self.imageView = imageView;
    
    // 添加标题
    UILabel *titleLabel = [[UILabel alloc] init];
    titleLabel.font = [UIFont systemFontOfSize:18];
    titleLabel.textColor = [UIColor darkGrayColor];
    [self addSubview:titleLabel];
    self.titleLabel = titleLabel;
    
    // 添加人数
    UILabel *numLabel = [[UILabel alloc] init];
    numLabel.font = [UIFont systemFontOfSize:14];
    numLabel.textAlignment = NSTextAlignmentRight;
    numLabel.textColor = [UIColor lightGrayColor];
    [self addSubview:numLabel];
    self.numLabel = numLabel;
    
}

/**
 调用父类布局子视图
 */
- (void)layoutSubviews {
    [super layoutSubviews];
    // 图标
    self.imageView.frame = CGRectMake(10, 10, 20, 20);
    
    // 标题
    CGFloat numW = 60;
    CGFloat titleX = CGRectGetMaxX(self.imageView.frame) + 10;
    CGFloat titleW = SCREEN_WIDTH - titleX - numW -15;
    self.titleLabel.frame = CGRectMake(titleX, 10, titleW, 20);
    
    // 人数
    CGFloat numX = SCREEN_WIDTH - numW - 10;
    self.numLabel.frame = CGRectMake(numX, 10, numW, 20);
}

#pragma mark - 监听事件
- (void)clickView:(UITapGestureRecognizer *)tapGes {
    if ([self.delegte respondsToSelector:@selector(friendHeaderReusableView:didSelectItemAtSection:)]) {
        [self.delegte friendHeaderReusableView:self didSelectItemAtSection:self.tag];
    }
}
@end

  • YDWFriendListShowCollectionViewCell:主要布局好友信息包括头像、昵称以及签名,具体实现如下:
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface YDWFriendListShowCollectionViewCell : UICollectionViewCell

@property(nonatomic,weak) UIImageView *imageView;
@property(nonatomic,weak) UILabel *nameLabel;
@property(nonatomic,weak) UILabel *detailsLabel;

@end

NS_ASSUME_NONNULL_END

#import "YDWFriendListShowCollectionViewCell.h"

@interface YDWFriendListShowCollectionViewCell ()

@end

@implementation YDWFriendListShowCollectionViewCell

#pragma mark - 初始化
- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubviews];
    }
    return self;
}

#pragma mark - 设置UI界面
- (void)addSubviews {
    // 添加图标
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.layer.cornerRadius = 50/2;
    imageView.layer.masksToBounds = YES;
    imageView.backgroundColor = [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0];
    [self addSubview:imageView];
    self.imageView = imageView;
    
    // 添加标题
    UILabel *nameLabel = [[UILabel alloc] init];
    nameLabel.font = [UIFont systemFontOfSize:18];
    nameLabel.textColor = [UIColor darkGrayColor];
    [self addSubview:nameLabel];
    self.nameLabel = nameLabel;
    
    // 添加签名
    UILabel *detailsLabel = [[UILabel alloc] init];
    detailsLabel.font = [UIFont systemFontOfSize:14];
    detailsLabel.textAlignment = NSTextAlignmentLeft;
    detailsLabel.textColor = [UIColor lightGrayColor];
    [self addSubview:detailsLabel];
    self.detailsLabel = detailsLabel;
    
}

/**
 调用父类布局子视图
 */
- (void)layoutSubviews {
    [super layoutSubviews];
    //1、图标
    self.imageView.frame = CGRectMake(10, 10, 50, 50);
    
    //2、标题
    CGFloat nameX = CGRectGetMaxX(self.imageView.frame) + 10;
    CGFloat nameW = SCREEN_WIDTH - nameX -10;
    self.nameLabel.frame = CGRectMake(nameX, 10, nameW, 20);
    
    //3、人数
    CGFloat detailsX = CGRectGetMaxX(self.imageView.frame) + 10;
    CGFloat detailsY = CGRectGetMaxY(self.nameLabel.frame) + 5;
    CGFloat detailsW = SCREEN_WIDTH - detailsX - 10;
    self.detailsLabel.frame = CGRectMake(detailsX, detailsY, detailsW, 20);
}
@end

③ 效果展示

在这里插入图片描述

使用 UITableView 实现

① 思路

  • 这个可以展开收缩的 UITableView,点击的是 TableView 的 section,每个 section 下面都对应一个数组,点击 section,就展开 section,然后展示数组数据。
  • 每次点击 section 都要刷新当前点击的这个 section,不用 reloadData,提高效率。
  • 那么点击的这个 section 怎么知道自己是展开呢还是折叠起来呢?那么关键就是对这里的处理,需要加一个条件判断是展开还是折叠。

② 实现方法

  • 可以用一个 boolArray 去记录每个 section 的状态,当然光记录还是不行的,还是不断的改变这个 boolArray 对应 section 的值,展开了就把值替换为 1,闭合了替换了0,那么这个 0 和 1 就是我们的依据,依据这个就可以返回这个 scetion 对应的 row。
  • 用一个类去记录和不断的替换状态,该 model 类增加一个状态判断的字段;

③ 流程

  • 控制器的代码:本类主要配置 UITableView 显示,以及处理组展开/关闭状态。
#import "YDWSecondViewController.h"
#import "YDWFriendListShowTableViewCell.h"
#import "YDWFriendHeadView.h"

static NSString * const kYDWFriendListShowTableViewCellIndentifier = @"YDWFriendListShowTableViewCell";
static NSString * const kYDWFriendHeadViewIndentifer = @"YDWFriendHeadView";


@interface YDWSecondViewController ()<UITableViewDelegate,UITableViewDataSource,FriendHeadViewDelegate>

@property (nonatomic, strong) UITableView *tableView;

@property(nonatomic,strong)   NSArray *headerArray;
@property (nonatomic, strong) NSMutableArray * dataArray;
@property (nonatomic, strong) NSMutableArray * boolArray;


@end

@implementation YDWSecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupNavigation];
    [self setupAddTableView];
    [self getListData];
}

#pragma mark - UITableViewDelegate,UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.dataArray.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if ([self.boolArray[section] boolValue] == NO) {
        return 0;
    } else {
        return [self.dataArray[section] count];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    YDWFriendListShowTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kYDWFriendListShowTableViewCellIndentifier];
    if (!cell) {
        cell = [[NSBundle mainBundle] loadNibNamed:@"YDWFriendListShowTableViewCell" owner:self options:nil].firstObject;
    }
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;
}

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

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    YDWFriendHeadView *headeView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kYDWFriendHeadViewIndentifer];
    if (headeView == nil) {
        headeView = [[YDWFriendHeadView alloc] initWithReuseIdentifier:kYDWFriendHeadViewIndentifer];
    }
    headeView.delegte = self;
    headeView.tag = section;
    headeView.imageView.image = [self.boolArray[section] boolValue] ? [UIImage imageNamed:[NSString stringWithFormat:@"zhankai"]] : [UIImage imageNamed:[NSString stringWithFormat:@"shouqi"]];
    
    headeView.titleLabel.text = self.headerArray[section];
    headeView.numLabel.text = [NSString stringWithFormat:@"%ld/%lu",(long)section, (unsigned long)[self.dataArray[section] count]];
    return headeView;
}

#pragma mark - FriendHeadViewDelegate
- (void)friendHeaderReusableView:(YDWFriendHeadView *)friendHeaderReusableView didSelectItemAtSection:(NSInteger)section {
    if ([self.boolArray[section] boolValue] == YES) {
        [self.boolArray replaceObjectAtIndex:section withObject:@NO];
    } else {
        [self.boolArray replaceObjectAtIndex:section withObject:@YES];
    }
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
}

#pragma mark - Private Methods
- (void)setupNavigation {
    self.navigationItem.title = @"联系人";
}

- (void)setupAddTableView {
    self.tableView.frame = self.view.bounds;
    [self.view addSubview:self.tableView];
}

- (void)getListData {
    // 准备组头的数据
    NSArray *headerArr = [NSArray arrayWithObjects:@"特别关心", @"我的好友", @"朋友", @"家人",nil];
    self.headerArray = headerArr;
    
    // 准备单元格的数据
    NSArray *itemArr = [NSArray arrayWithObjects:@5, @10, @7,@3,  nil];
    for (int i = 0; i < self.headerArray.count; i++) {
        // 所有的分组默认关闭
        [self.boolArray addObject:@NO];
        
        // 给每个分组添加数据
        NSMutableArray * friendArr = [[NSMutableArray alloc] init];
        for (int j = 0; j < [itemArr[i] intValue]; j++) {
            [friendArr addObject:@(j)];
        }
        [self.dataArray addObject:friendArr];
        
    }
    [self.tableView reloadData];
}


#pragma mark - Lazying Load
- (NSMutableArray *)boolArray {
    if (!_boolArray) {
        _boolArray = [[NSMutableArray alloc] init];
    }
    return _boolArray;
}

- (NSMutableArray *)dataArray {
    if (!_dataArray) {
        _dataArray = [[NSMutableArray alloc] init];
    }
    return _dataArray;
}

- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc] init];
        _tableView.backgroundColor = [UIColor whiteColor];
        _tableView.showsHorizontalScrollIndicator = NO;
        _tableView.delegate = self;
        _tableView.dataSource = self;
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        _tableView.tableFooterView = [UIView new];
        [_tableView registerClass:[YDWFriendHeadView class] forHeaderFooterViewReuseIdentifier:kYDWFriendHeadViewIndentifer];

    }
    return _tableView;
}

@end

  • YDWFriendHeadView:本类主要布局组标题以及指示(展开/关闭)控件,其次,通过添加点击手势结合委托模式,传递 tag 值。
NS_ASSUME_NONNULL_BEGIN
@class YDWFriendHeadView;
@protocol FriendHeadViewDelegate <NSObject>

- (void)friendHeaderReusableView:(YDWFriendHeadView *)friendHeaderReusableView didSelectItemAtSection:(NSInteger)section;

@end

@interface YDWFriendHeadView : UITableViewHeaderFooterView

@property(nonatomic,weak) id <FriendHeadViewDelegate>delegte;

/**
 图标
 */
@property(nonatomic,weak) UIImageView *imageView;
/**
 标题
 */
@property(nonatomic,weak) UILabel *titleLabel;
/**
 人数
 */
@property(nonatomic,weak) UILabel *numLabel;
@end

NS_ASSUME_NONNULL_END

#import "YDWFriendHeadView.h"

@implementation YDWFriendHeadView

#pragma mark - 初始化
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
        self.userInteractionEnabled = YES;
        self.contentView.backgroundColor = [UIColor whiteColor];
        UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickView:)];
        [self addGestureRecognizer:tapGes];
        [self addSubviews];
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];
    [self addSubviews];
}

#pragma mark - 设置UI界面
- (void)addSubviews {
    // 添加图标
    UIImageView *imageView = [[UIImageView alloc] init];
    [self addSubview:imageView];
    self.imageView = imageView;
    
    // 添加标题
    UILabel *titleLabel = [[UILabel alloc] init];
    titleLabel.font = [UIFont systemFontOfSize:18];
    titleLabel.textColor = [UIColor darkGrayColor];
    [self addSubview:titleLabel];
    self.titleLabel = titleLabel;
    
    // 添加人数
    UILabel *numLabel = [[UILabel alloc] init];
    numLabel.font = [UIFont systemFontOfSize:14];
    numLabel.textAlignment = NSTextAlignmentRight;
    numLabel.textColor = [UIColor lightGrayColor];
    [self addSubview:numLabel];
    self.numLabel = numLabel;
    
}

/**
 调用父类布局子视图
 */
- (void)layoutSubviews {
    [super layoutSubviews];
    // 图标
    self.imageView.frame = CGRectMake(10, 10, 20, 20);
    
    // 标题
    CGFloat numW = 60;
    CGFloat titleX = CGRectGetMaxX(self.imageView.frame) + 10;
    CGFloat titleW = SCREEN_WIDTH - titleX - numW -15;
    self.titleLabel.frame = CGRectMake(titleX, 10, titleW, 20);
    
    // 人数
    CGFloat numX = SCREEN_WIDTH - numW - 10;
    self.numLabel.frame = CGRectMake(numX, 10, numW, 20);
}

#pragma mark - 监听事件
- (void)clickView:(UITapGestureRecognizer *)tapGes {
    if ([self.delegte respondsToSelector:@selector(friendHeaderReusableView:didSelectItemAtSection:)]) {
        [self.delegte friendHeaderReusableView:self didSelectItemAtSection:self.tag];
    }
}
@end

  • YDWFriendListShowTableViewCell:主要布局好友信息包括头像、昵称以及签名,具体实现如下:
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface YDWFriendListShowTableViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UIImageView *headImageView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UILabel *signLabel;

@end

NS_ASSUME_NONNULL_END

#import "YDWFriendListShowTableViewCell.h"

@implementation YDWFriendListShowTableViewCell

- (void)awakeFromNib {
    [super awakeFromNib];
    
    self.headImageView.backgroundColor = [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0];
    [self.headImageView.layer setMasksToBounds:YES];
    [self.headImageView.layer setCornerRadius:25];

}


- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    
}
@end

④ 效果展示

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
iOS中的tableView是一种用于展示大量数据的常见控件,而多级展开折叠则是一种实现tableView中展示层级关系的常见需求,类似于QQ好友列表效果实现这个效果的方法是通过tableView的数据源和代理方法来控制每个cell的样式和交互。以下是一个简单的实现步骤: 1. 设计数据模型:根据层级关系设计一个合适的数据模型,每个模型中包含展开折叠状态、子模型等相关属性。 2. 创建tableView:在界面上创建一个tableView,并设置其数据源和代理为当前控制器。 3. 实现数据源方法:在数据源方法中,根据模型的展开折叠状态来确定每个cell的样式和数量。 4. 实现代理方法:在代理方法中,根据用户的操作(点击或者滑动等)来更新模型的展开折叠状态,并刷新tableView。 5. 自定义cell:根据不同的展开折叠状态,自定义cell的样式和布局。 6. 添加动画效果:为了增加用户体验,在展开折叠的过程中可以添加一些动画效果,比如cell的展开和折叠、tableView的滚动等。 7. 处理点击事件:根据用户的点击来判断是展开还是折叠,并更新对应的模型和tableView。 8. 优化性能:如果数据量较大,可以考虑使用懒加载或者异步加载等方式来减少内存占用和提高性能。 通过以上步骤,我们就可以实现类似QQ好友列表的多级展开折叠效果。当用户点击某个cell时,可以展开其子级内容,再次点击则折叠子级内容,以此类推,完成多级展开折叠的功能。 需要注意的是,实现这个效果需要根据具体的需求和设计来确定数据模型、点击事件和界面样式等方面的实现细节。以上是一个基本的实现思路,具体的实现过程可能会因具体的需求而有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

╰つ栺尖篴夢ゞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值