美文网首页iOS开发iOS界面特效篇UI的实现
iOS开发-仿QQ好友列表展开/关闭

iOS开发-仿QQ好友列表展开/关闭

作者: it_hao528 | 来源:发表于2016-12-03 14:23 被阅读938次

    前言:前端时间小编的一个朋友要做一个类似QQ列表的展开与关闭的效果,于是小编在闲暇之余给他写了一个demo,本着好东西大家一起来分享的精神,趁着今天有时间小编把这个demo在此与大家一起共享,希望能够帮到有需要的朋友。

    原理:使用UITableView列表形式,对sectionHeaderView添加tap手势,点击展开/关闭该section通过对每个section记录一个是否展开的BOOL值来实现。

    小编没有做很细化的效果,先看看简单效果图如下:


    未展开.png
    展开.png

    下面来介绍代码的实现:
    由于没有网络数据,小编只能自己伪造了一些假数据,大家在使用的时候替换掉就可以了。

    #import "ViewController.h"
    #import "QQFriendCell.h"
    
    #define Cell_QQFriend   @"Cell_QQFriend_ID"
    
    @interface ViewController () <UITableViewDelegate, UITableViewDataSource>
    
    @property (nonatomic, strong) UITableView * tableView;
    //总数据
    @property (nonatomic, strong) NSMutableArray * dataArr;
    //每组的标题
    @property (nonatomic, strong) NSMutableArray * sectionArr;
    //存储是否展开的BOOL值
    @property (nonatomic, strong) NSMutableArray * boolArr;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.title = @"好友列表";
        [self loadData];
        [self addSubviews];
        [self makeConstraintsForUI];
    }
    
    //加载数据
    - (void)loadData {
        
        NSArray * secArr = @[@"我的好友", @"小学同学", @"初中同学", @"高中同学", @"大学同学"];
        NSArray * rowsArr = @[@(12), @(10), @(15), @(13), @(22)];
        
        for (int i = 0; i < secArr.count; i++) {
            
            NSMutableArray * friendArr = [[NSMutableArray alloc] init];
            for (int j = 0; j < [rowsArr[i] intValue]; j++) {
                
                [friendArr addObject:@(j)];
            }
            [self.dataArr addObject:friendArr];
            [self.sectionArr addObject:secArr[i]];
            [self.boolArr addObject:@NO];
        }
    }
    
    #pragma mark - add subviews
    
    - (void)addSubviews {
        
        [self.view addSubview:self.tableView];
    }
    
    #pragma mark - make constraints
    
    - (void)makeConstraintsForUI {
        
        [_tableView mas_makeConstraints:^(MASConstraintMaker *make) {
            
            make.size.mas_equalTo(CGSizeMake(Screen_Width, Screen_Height));
            make.left.mas_equalTo(@0);
            make.top.mas_equalTo(@0);
        }];
    }
    
    #pragma mark - tableView delegate and dataSource
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        
        return self.dataArr.count;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
        //判断是否展开,如果未展开则返回0
        if ([self.boolArr[section] boolValue] == NO) {
            
            return 0;
        }else {
            
            return [self.dataArr[section] count];
        }
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        
        QQFriendCell * cell = [tableView dequeueReusableCellWithIdentifier:Cell_QQFriend forIndexPath:indexPath];
        
        if (indexPath.row < [self.dataArr[indexPath.section] count]) {
            //这里可以传入请求的数据,此方法可以根据自己的需求做更改
            [cell configCellWithData:nil row:indexPath.row];
        }
        return cell;
    }
    
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
        
        //创建header的view
        UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, Screen_Width, 50)];
        headerView.tag = 2016 + section;
        headerView.backgroundColor = [UIColor colorWithRed:235/255.0 green:235/255.0 blue:235/255.0 alpha:1];
        
        //添加imageview
        UIImageView * iv = [[UIImageView alloc] initWithFrame:CGRectMake(10, 15, 20, 20)];
        
        //三目运算选择展开或者闭合时候的图标
        iv.image = [_boolArr[section] boolValue] ? [UIImage imageNamed:@"buddy_header_arrow_down"] : [UIImage imageNamed:@"buddy_header_arrow_right"];
        [headerView addSubview:iv];
        
        //添加标题label
        UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(35, 0, Screen_Width - 100, 50)];
        label.text = self.sectionArr[section];
        [headerView addSubview:label];
        
        //添加分组人数和在线人数显示的label
        UILabel * labelR = [[UILabel alloc] initWithFrame:CGRectMake(Screen_Width - 60, 0, 60, 50)];
        labelR.textAlignment = NSTextAlignmentCenter;
        //这里小编把在线人数全部设置成了0,可以根据需求更改
        labelR.text = [NSString stringWithFormat:@"%d/%lu", 0, [self.dataArr[section] count]];
        [headerView addSubview:labelR];
        
        //添加轻扣手势
        UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGR:)];
        [headerView addGestureRecognizer:tap];
        
        return headerView;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
        
        return 50;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        
        return 70;
    }
    
    #pragma mark - action
    - (void)tapGR:(UITapGestureRecognizer *)tapGR {
        
        //获取section
        NSInteger section = tapGR.view.tag - 2016;
        //判断改变bool值
        if ([_boolArr[section] boolValue] == YES) {
            [_boolArr replaceObjectAtIndex:section withObject:@NO];
        }else {
            [_boolArr replaceObjectAtIndex:section withObject:@YES];
        }
        //刷新某个section
        [_tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
    }
    
    #pragma mark - setter and getter
    
    - (UITableView *)tableView {
        
        if (!_tableView) {
            
            _tableView = [[UITableView alloc] init];
            _tableView.delegate = self;
            _tableView.dataSource = self;
            [_tableView registerClass:[QQFriendCell class] forCellReuseIdentifier:Cell_QQFriend];
            //下面这行代码可以避免分组都没展开时,空白处出现的横线
            _tableView.tableFooterView = [[UIView alloc] init];
        }
        return _tableView;
    }
    
    - (NSMutableArray *)dataArr {
        
        if (!_dataArr) {
            
            _dataArr = [[NSMutableArray alloc] init];
        }
        return _dataArr;
    }
    
    - (NSMutableArray *)sectionArr {
        
        if (!_sectionArr) {
            
            _sectionArr = [[NSMutableArray alloc] init];
        }
        return _sectionArr;
    }
    
    - (NSMutableArray *)boolArr {
        
        if (!_boolArr) {
            
            _boolArr = [[NSMutableArray alloc] init];
        }
        return _boolArr;
    }
    
    @end
    

    上边是ViewController里边的代码,小编对Cell也进行了简单的定制,同时SectionHeaderView在此写的有些复杂,代码比较多,其实可以单独拉出来进行定制,定制之后再次调用会看起来清爽很多,但是小编时间有限就没有定制,只是对Cell进行了简单的定制,在此只看.m中的代码即可:

    #import "QQFriendCell.h"
    
    @interface QQFriendCell ()
    //头像
    @property (nonatomic, strong) UIImageView * image_icon;
    //昵称
    @property (nonatomic, strong) UILabel * lab_nickname;
    //签名
    @property (nonatomic, strong) UILabel * lab_signature;
    @end
    @implementation QQFriendCell
    
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
        
        self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
        
        if (self) {
            
            [self addSubviews];
        }
        return self;
    }
    
    #pragma mark - add subviews
    
    - (void)addSubviews {
        
        [self addSubview:self.image_icon];
        [self addSubview:self.lab_nickname];
        [self addSubview:self.lab_signature];
    }
    
    #pragma mark - layout subviews
    
    - (void)layoutSubviews {
        
        [super layoutSubviews];
        
        [_image_icon mas_makeConstraints:^(MASConstraintMaker *make) {
            
            make.size.mas_equalTo(CGSizeMake(50, 50));
            make.left.mas_equalTo(@15);
            make.top.mas_equalTo(@10);
        }];
        
        [_lab_nickname mas_makeConstraints:^(MASConstraintMaker *make) {
            
            make.top.mas_equalTo(_image_icon.mas_top);
            make.left.mas_equalTo(_image_icon.mas_right).with.offset(15);
            make.right.mas_equalTo(@-15);
            make.height.mas_equalTo(@21);
        }];
        
        [_lab_signature mas_makeConstraints:^(MASConstraintMaker *make) {
            
            make.bottom.mas_equalTo(_image_icon.mas_bottom);
            make.left.mas_equalTo(_lab_nickname.mas_left);
            make.right.mas_equalTo(_lab_nickname.mas_right);
            make.height.mas_equalTo(@21);
        }];
    }
    
    #pragma mark - config cell
    //此方法为外漏方法,可以根据自己的需求更改
    - (void)configCellWithData:(NSDictionary *)dic row:(NSInteger)row {
        
        _image_icon.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1.0];
        _lab_nickname.text = [NSString stringWithFormat:@"好友%lu", row + 1];
        _lab_signature.text = [NSString stringWithFormat:@"这是好友%lu的签名", row + 1];
    }
    
    #pragma mark - setter and getter
    
    - (UIImageView *)image_icon {
        
        if (!_image_icon) {
            
            _image_icon = [[UIImageView alloc] init];
            _image_icon.contentMode = UIViewContentModeScaleAspectFill;
            _image_icon.layer.cornerRadius = 25.0;
            _image_icon.layer.masksToBounds = YES;
        }
        return _image_icon;
    }
    
    - (UILabel *)lab_nickname {
        
        if (!_lab_nickname) {
            
            _lab_nickname = [[UILabel alloc] init];
            _lab_nickname.font = [UIFont systemFontOfSize:18];
        }
        return _lab_nickname;
    }
    @end
    

    看到这里就结束了,是不是很简单呢,其实只要知道点击展开/关闭的原理,相信大家都可以写出效果来的。

    总结一下此demo用到的几个关键的点:
    1、需要一个存储各个分组是否展开的BOOL值的数组;
    2、tableView刷新某个Section的动态方法

    demo下载地址:https://github.com/guorenhao/TencentQQ.git

    最后,小编还是希望此文能够帮助到有需要的朋友们,愿同是程序猿的我们能够共同学习进步,在开发的道路上越走越远!谢谢!

    相关文章

      网友评论

      • Lee0528:分组长按拖动知道怎么实现吗?
        Lee0528:@Abner_G 嗯嗯 我想的也是那个,就是想看看有没有直接可以拖动的效果
        it_hao528:@Lee0528 没试过,不过我的思路是长按之后进入编辑模式进行拖动,你可以试试
      • c2fffd2b0090:这个可以点击另外一组,其他组关闭吗?
        it_hao528:@打了鸡血 这个没有做那样的逻辑,不过你可以在点击组那里做相应的修改就可以实现了
      • Berning:如今小编都会写代码了。程序猿要饿死了。。。 :scream:
        it_hao528:@Berning 小编也是一枚程序猿哈!:relaxed:
      • L泽:那个三角形是代码写的,不是图片:smirk:
        it_hao528:@L大帝 我这里用的是图片,简单一些:blush:
      • 飞翔fly:总体写的不错,如果代码抽离出来自定义每个分区标题控件会更好😀
        it_hao528:嗯,写的有点急,没有做很细的封装,以后会好好改进,谢谢你的建议!
      • a8f1b2fc0268:大神加油!
      • a8f1b2fc0268:大神加油!期待你下一次作品
        it_hao528:不敢当,希望能帮到有需要的朋友。

      本文标题:iOS开发-仿QQ好友列表展开/关闭

      本文链接:https://www.haomeiwen.com/subject/mslcmttx.html