day01好友列表折叠效果实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了day01好友列表折叠效果实现相关的知识,希望对你有一定的参考价值。

1.实现效果

技术分享          技术分享

2.关键点:每个分组的展开和折叠,主要是对每组的行数进行设置,展开为count,折叠为0

3.思想思路:先实现数据模型逻辑-->展示基本数据-->自定义cell-->自定义cellHeaderView视图-->在cellHeaderView中设置协议,controller中遵守协议,实现cellHeaderView点击事件的传递(即好友列表折叠点击事件的实现)

4.主要代码

1)friend ,group数据模型的定义

 1 //
 2 //  FriendModel.h
 3 //  1.自定义cell(纯代码)
 4 //
 5 //  Created by 许霞 on 16/9/7.
 6 //  Copyright © 2016年 jmchat. All rights reserved.
 7 //
 8 
 9 #import <Foundation/Foundation.h>
10 
11 @interface FriendModel : NSObject
12 /**
13  *  图片
14  */
15 @property (nonatomic,copy) NSString *icon;
16 /**
17  *  介绍
18  */
19 @property (nonatomic,copy) NSString *intro;
20 /**
21  * 姓名
22  */
23 @property (nonatomic,copy) NSString *name;
24 /**
25  *  是否是vip
26  */
27 @property (nonatomic,assign,getter=isVip) BOOL vip;
28 
29 - (instancetype)initWithDict:(NSDictionary *)dict;
30 + (instancetype)friendModelWithDict:(NSDictionary *)dict;
31 @end
//
//  FriendModel.m
//  1.自定义cell(纯代码)
//
//  Created by 许霞 on 16/9/7.
//  Copyright © 2016年 jmchat. All rights reserved.
//

#import "FriendModel.h"

@implementation FriendModel
- (instancetype)initWithDict:(NSDictionary *)dict
{
    if (self =[super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

+ (instancetype)friendModelWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}
@end
//
//  GroupModel.h
//  1.自定义cell(纯代码)
//
//  Created by 许霞 on 16/9/7.
//  Copyright © 2016年 jmchat. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface GroupModel : NSObject
/**
 *  姓名
 */
@property (nonatomic,copy) NSString *name;
/**
 *  在线数
 */
@property (nonatomic,assign) int online;

/**
 *  朋友
 */

@property (nonatomic,strong) NSArray *friends;

/**
 *  是否展开
 */
@property (nonatomic,assign,getter=isOpened) BOOL opened;

+ (instancetype)groupModelWithDict:(NSDictionary *)dict;

- (instancetype)initWithDict:(NSDictionary *)dict;
@end
//
//  GroupModel.m
//  1.自定义cell(纯代码)
//
//  Created by 许霞 on 16/9/7.
//  Copyright © 2016年 jmchat. All rights reserved.
//

#import "GroupModel.h"
#import "FriendModel.h"
@implementation GroupModel
+ (instancetype)groupModelWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}

- (instancetype)initWithDict:(NSDictionary *)dict
{
    if (self =[super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    NSMutableArray * friendArray =[NSMutableArray array];
    for (NSDictionary * friendDict in _friends) {
        FriendModel * friend =[FriendModel friendModelWithDict:friendDict];
        [friendArray addObject:friend];
    }
    _friends = friendArray;
    return self;
}

@end

2)cell,headerView的定义

//
//  FriendTableViewCell.h
//  1.自定义cell(纯代码)
//
//  Created by 许霞 on 16/9/7.
//  Copyright © 2016年 jmchat. All rights reserved.
//

#import <UIKit/UIKit.h>
@class FriendModel;
@interface FriendTableViewCell : UITableViewCell
@property (nonatomic,strong) FriendModel * friendData;
+(instancetype) cellWithTableView:(UITableView *)tableView;

@end
//
//  FriendTableViewCell.m
//  1.自定义cell(纯代码)
//
//  Created by 许霞 on 16/9/7.
//  Copyright © 2016年 jmchat. All rights reserved.
//

#import "FriendTableViewCell.h"
#import "FriendModel.h"
@implementation FriendTableViewCell
+(instancetype)cellWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"friend";
    FriendTableViewCell * cell =[tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[FriendTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    return cell;
}

- (void)setFriendData:(FriendModel *)friendData

{
    _friendData = friendData;
    self.textLabel.text =_friendData.name;
    self.detailTextLabel.text = _friendData.intro;
    self.imageView.image =[UIImage imageNamed:_friendData.icon];
    self.textLabel.textColor = _friendData.isVip?[UIColor redColor]:[UIColor blackColor];

}

@end
//
//  GroupHeaderView.h
//  1.自定义cell(纯代码)
//
//  Created by 许霞 on 16/9/7.
//  Copyright © 2016年 jmchat. All rights reserved.
//

#import <UIKit/UIKit.h>
@class GroupModel,GroupHeaderView;

@protocol  GroupHeaderViewDelegate <NSObject>

@optional
- (void)headerViewDidClickedNameView:(GroupHeaderView *)headerView;

@end
@interface GroupHeaderView : UITableViewHeaderFooterView
@property (nonatomic, strong) GroupModel * group;
@property (nonatomic, weak) id <GroupHeaderViewDelegate> delegate;
+(instancetype)headerViewWithTableView:(UITableView *)tableView;
- (void)updateHeaderView;
@end
//
//  GroupHeaderView.m
//  1.自定义cell(纯代码)
//
//  Created by 许霞 on 16/9/7.
//  Copyright © 2016年 jmchat. All rights reserved.
//

#import "GroupHeaderView.h"
#import "GroupModel.h"
@interface GroupHeaderView ()
@property (nonatomic,weak) UILabel * countView;
@property (nonatomic,weak) UIButton *nameView;
@end
@implementation GroupHeaderView
+(instancetype)headerViewWithTableView:(UITableView *)tableView;
{
    static NSString *ID =@"groupHeader";
    GroupHeaderView * header =[tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
    if (header == nil) {
        header =[[GroupHeaderView alloc] initWithReuseIdentifier:ID];
    }
    return header;
}

- (id) initWithReuseIdentifier:(NSString *)reuseIdentifier
{
    if (self =[super initWithReuseIdentifier:reuseIdentifier]) {
        //1.添加子控件
        UIButton * nameView =[UIButton buttonWithType:UIButtonTypeCustom];
        [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];
        [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];
        [nameView setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];
        [nameView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        nameView.titleEdgeInsets =UIEdgeInsetsMake(0, 10, 0, 0);
        nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
        nameView.imageView.contentMode = UIViewContentModeCenter;
        nameView.imageView.clipsToBounds = NO;
        [nameView addTarget:self action:@selector(nameViewClick) forControlEvents:UIControlEventTouchUpInside];
        [self.contentView addSubview:nameView];
        self.nameView = nameView;
        
        UILabel *countView =[[UILabel alloc] init];
        countView.textAlignment = NSTextAlignmentRight;
        countView.textColor = [UIColor grayColor];
        [self.contentView addSubview:countView];
        self.countView = countView;
    }
    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    self.nameView.frame = self.bounds;
    
    CGFloat countY = 0;
    CGFloat countH =self.nameView.frame.size.height;
    CGFloat countW = 150;
    CGFloat countX =  self.frame.size.width-10-countW;
    self.countView.frame = CGRectMake(countX, countY, countW, countH);
    
}

-(void)setGroup:(GroupModel *)group
{
    _group = group;
    [self.nameView setTitle:group.name forState:UIControlStateNormal];
    self.countView.text =[NSString stringWithFormat:@"%d/%u",group.online,group.friends.count];
}

- (void)nameViewClick
{
    self.group.opened = !self.group.opened;

    if ([self.delegate respondsToSelector:@selector(headerViewDidClickedNameView:)]) {
        [self.delegate headerViewDidClickedNameView:self];
    }
}

- (void)updateHeaderView
{
    if (self.group.opened) {
        self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
    }else{
        self.nameView.imageView.transform = CGAffineTransformMakeRotation(0);
    }
    

}

//- (void)willMoveToSuperview:(UIView *)newSuperview
//{
//    if (self.group.opened) {
//        self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
//    }else{
//        self.nameView.imageView.transform = CGAffineTransformMakeRotation(0);
//    }
//}
@end

 

3)controller的实现

  1 //
  2 //  ViewController.m
  4 //
  5 //  Created by 许霞 on 16/9/7.
  6 //  Copyright © 2016年 jmchat. All rights reserved.
  7 //
  8 
  9 #import "ViewController.h"
 10 #import "GroupModel.h"
 11 #import "FriendModel.h"
 12 #import "FriendTableViewCell.h"
 13 #import "GroupHeaderView.h"
 14 
 15 @interface ViewController ()<UITableViewDataSource,UITableViewDelegate,GroupHeaderViewDelegate>
 16 @property (nonatomic,strong) UITableView * tableView;
 17 @property (nonatomic,strong) NSArray * dataArray;
 18 @end
 19 
 20 @implementation ViewController
 21 
 22 - (void)viewDidLoad {
 23     [super viewDidLoad];
 24     [self initUI];
 25 }
 26 /**
 27  *  懒加载实现数据的加载
 28  */
 29 
 30 - (NSArray *)dataArray
 31 {
 32     if (_dataArray ==nil) {
 33         NSArray * dictArray =[[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil] ];
 34         NSMutableArray *groups =[NSMutableArray array];
 35         for (NSDictionary * groupDict in dictArray) {
 36             GroupModel * group =[GroupModel groupModelWithDict:groupDict];
 37             [groups addObject:group];
 38         }
 39         _dataArray = groups;
 40     }
 41     return _dataArray;
 42 }
 43 
 44 - (void) initUI
 45 {
 46     self.tableView.autoresizesSubviews = NO;
 47     self.tableView =[[UITableView alloc] initWithFrame:CGRectMake(0, 20, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) style:UITableViewStylePlain];
 48     _tableView.delegate =self;
 49     _tableView.dataSource =self;
 50     _tableView.rowHeight = 50.0f;
 51     _tableView.sectionHeaderHeight = 44.0f;
 52     [self.view addSubview:_tableView];
 53 }
 54 #pragma  mark-
 55 #pragma  mark-UITableViewDataSource
 56 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 57 {
 58     return self.dataArray.count;
 59 }
 60 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 61 {
 62     GroupModel * group = self.dataArray[section];
 63     return group.opened? group.friends.count:0;
 64 }
 65 
 66 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 67 {
 68     //1.创建cell
 69     FriendTableViewCell * cell =[FriendTableViewCell cellWithTableView:tableView];
 70     //2.设置cell数据
 71     GroupModel * group =self.dataArray[indexPath.section];
 72     FriendModel * friendData = group.friends[indexPath.row];
 73     cell.friendData = friendData;
 74     
 75     
 76     return cell;
 77 }
 78 
 79 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
 80 {
 81     return 30.0f;
 82 }
 83 
 84 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
 85 {
 86     //1.创建头部控件
 87     GroupHeaderView * headerView =[GroupHeaderView headerViewWithTableView:tableView];
 88     headerView.delegate =self;
 89     //2.给Header设置数据(传递模型给header)
 90     headerView.group =self.dataArray[section];
 91     [headerView updateHeaderView];
 92     
 93     return headerView;
 94 }
 95 
 96 #pragma mark-
 97 #pragma  mark --GroupHeaderViewDelegate
 98 - (void)headerViewDidClickedNameView:(GroupHeaderView *)headerView
 99 {
100     [self.tableView reloadData];
101 }
102 
103 
104 @end

5.经验总结

1)隐藏显示状态栏方法

-(BOOL)prefersStatusBarHidden

{

    return YES;

}

2)friend 是c++关键字,不能用friend作为属性名

3)当一个控件被添加到父控件的中就会调用

- (void)didMoveToSuperView

{

}

4)headerView和cell一样,都有一个复用机制,但是当刷新tableVIew的时候,是不会从缓存池中取的,而是重新创建

5)layoutSubviews (一般在这里布局内部的子控件,设置子控件的frame,当一个控件的frame发生改变的时候就会调用)

6)tableView 的类型如果是plain可以实现组头固定显示;如果是group则无此效果,且如果为plain类型, 设置其组头,组为的高度为0有效,而group类型则无效,但可以设置为0.000001等极小数,可以实现组头,组尾视图的高度设置;

7)将数据源数组设置为不可变,是保证数据安全,不会被合作程序员不小心修改,也是让合作者透露,此数据源数组,不能更改

8)懒加载是写在get方法,如果你需要的时候,才会创建,而if(_group==nil),这里一定不能使用self.group,这样会导致循环调用

9)当模型中又包含有其他模型时,我们需要对其模型部分进行处理,大致思路仍是:用kvc实现复制,但是包含模型部分的数据,被kvc设置为了普通数据,我们单独对此部分进行重新设置即可,关键代码如下:

-(instancetype)initWithDict:(NSDictionary *)dict

{

 if (self =[super init]){

//1.注入所有属性

[self setValuesForKeysWithDictionary:dict];

//2.特殊处理friends属性

NSMutabelArray *friendArray =[NSMutableArray array];

for (NSDictionary *dict in self.friends)

{

 Friend * friend =[Friend friendWithDict:dict];

 [friendArray addObject:friend];

}

self.friends = friendArray;

}

return self;

}

10)代码仓库不确定的<#type#>进行设置

11)BOOL值属性,我们一般通过,getter关键字对其重命名

@property (nonatomic,assign,getter = isVip) BOOL vip

12)如果某个控件不出来,可以考虑的原因如下:

1.frame的尺寸和位置对不对; 2.hidden是否为YES; 3.有没有添加到父控件中; 4.alpha 是否 < 0.01; 5.被其他控件挡住了 ;6.父控件的前面5个情况.

13)按钮的一些属性:

1.设置按钮的内容的对齐方式:(垂直方向上:上下对齐;水平方向上:左右对齐)

nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

2.设置按钮的图片,文字,整体内容的内边距(这里内边距对象格式为:上左下右,逆时针方向设置)

 nameView.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);

 nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);

3.设置按钮的内容,文字,图片的显示模式

 nameView.imageView.contentMode = UIViewContentModeCenter;

4.设置按钮图片超过边框的内容是否裁剪

 nameView.imageView.clipsToBounds = NO;

 

以上是关于day01好友列表折叠效果实现的主要内容,如果未能解决你的问题,请参考以下文章

JS实例之列表选中,实现类似好友列表选中效果

仿QQ好友列表界面的实现

Avalonia跨平台入门第十四篇之ListBox折叠列表

Qt之使用QTreeView实现QQ好友列表

Qt之使用QTreeView实现QQ登录好友列表

小程序如何实现一个可折叠的列表