UI025: 好友列表實(shí)現(xiàn)

界面效果

// 好友列表實(shí)現(xiàn)
UITableViewController, 設(shè)置起始控制器膏萧。
新建CZQQFriendsTableViewController 繼承自 UITableViewController
設(shè)置給storyBoard的Class北专。



// 模型嵌套刁赖。好友模型

#import <Foundation/Foundation.h>
@interface CZFriend :NSObject
@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *intro;
@property (nonatomic, assign, getter = isVip) BOOL vip;

- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)friendWithDict:(NSDictionary *)dict;
@end

//----------------------

#import "CZFriend.h"
@implementation CZFriend
- (instancetype)initWithDict:(NSDictionary *)dict
{
    if(self = [super init]){
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}
+ (instancetype)friendWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}
@end

// 分組模型

#import <Foundation/Foundation.h>
@interface CZGroup : NSObject
// 組名,在線人數(shù)并炮,當(dāng)前組的好友數(shù)據(jù)。
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int online;
@property (nonatomic, strong) NSArray *friends;
// 組的折疊狀態(tài)媚创。
@property (nonatomic, assign, getter=isVisible) BOOL *visible;

- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)groupWithDict:(NSDictionary *)dict;
@end

//----------------------
#import "CZGroup.h"
#import "CZFriend.h"
@implementation CZGroup
- (instancetype)initWithDict:(NSDictionary *)dict
{
    if(self = [super init]){
        [self setValuesForKeysWithDictionary:dict];
        
        // self.friends中,字典數(shù)組轉(zhuǎn)模型數(shù)據(jù)
        NSMutableArray *arrayModels = [NSMutableArray array];
        for(NSDictionary *dict_sub in self.friends) {
            CZFriend *model = [CZFriend friendWithDict:dict_sub];
            [arrayModels addObject:model];
        }
        self.friends = arrayModels;
    }
    return self;
}
+ (instancetype)groupWithDict:(NSDictionary *)dict
{
    return [[self alloc] initWithDict:dict];
}
@end

// 自定義Cell:CZFriendCell

// CZFriendCell.h
@class CZFriend;
@interface CZFriendCell : UITableViewCell
@property(nonatomic, strong) CZFriend *friendModel;

+ (instancetype)friendCellWithTableView:(UITableView *)tableView;
@end
//----------------------
// CZFriendCell.m
@implementation CZFriendCell
+ (instancetype)friendCellWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"friend_cell";
    CZFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if(cell == nil) {
        cell = [[CZFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    } 
    return cell;
}
- (void)setFriendModel:(CZFriend *)friendModel 
{
    _friendModel = friendModel;
    self.imageView.image = [UIImage imageNamed:friendModel.icon];
    self.textLabel.text = friendModel.name;
    self.detailTExtLabel.text = friendModel.intro;
    // 判斷是否vip航瞭,將昵稱(chēng)顯示紅色或黑色
    self.textLabel.text.textColor = friendModel.isVip 
        ? [UIColor redColor]
        : [UIColor blackColor];
}
- (void)awakeFromNib {
}
@end

// 自定義headerView诫硕。
// UITableViewHeaderFooterView

// 10.1新增代理協(xié)議
@class CZGroupHeaderView;
@protocol CZGroupHeaderViewDelegate <NSObject>
- (void)groupHeaderViewDidClickClickTitleButton:(CZGroupHeaderView *)groupHeaderVIew;
@end

@class CZGroup;
@interface CZGroupHeaderView : UITableViewHeaderFooterView
@property (nanotomic, strong) CZGroup *group;
+(instancetype)groupHeaderViewWithTableView:(UITableView *)tableView;
// 10.2新增代理屬性
@property (nanotomic, weak) id<CZGroupHeaderViewDelegate> delegate;
@end

//-----------------------

@interface CZGroupHeaderView ()
@property(nonatomic, weak) UIButton *btnGroupTitle;
@property(nonatomic, weak) UILabel *lblCount;
@end

@implementation CZGroupHeaderView
// 重寫(xiě)group的setGroup方法。
-(void)setGroup: (CZGroup *)group
{
    _group = group;
    [self.btnGroupTitle setTitle:group.name forState:UIControlStateNormal];
    self.lblCount.text = [NSString stringWithFormat:@"%d / %d", group.online, group.friends.count];
    // 設(shè)置按鈕中圖片的旋轉(zhuǎn)問(wèn)題刊侯。
    if (self.group.isVisible) {
        // 3.修改按鈕圖片章办,讓按鈕旋轉(zhuǎn)90度。
        self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
    } else { // 旋轉(zhuǎn)回到原來(lái)的位置
        self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(0);
    }
    // 不要將設(shè)置frame的方法寫(xiě)在這里滨彻,因?yàn)榇颂帿@取的self的frame寬高信息都是0.
}

// 當(dāng)當(dāng)前控件的frame發(fā)生改變的時(shí)候藕届,調(diào)用。
- (void)layoutSubViews {
    [super layoutSubViews];
    // 設(shè)置按鈕的frame亭饵,設(shè)置labelframe
    self.btnGroup.frame = self.bounds;

    CGFloat lblW = 100;
    CGFloat lblH = self.bounds.size.height;
    CGFloat lblX = self.bounds.size.width -10 - lblW;
    CGFloat lblY = 0;
    self.lblCount.frame = CGRectMake(lblX, lblY, lblW, lblH);
}

// 封裝類(lèi)方法休偶,創(chuàng)建headerVIew
+ (instancetype)groupHeaderViewWithTableView:(UITableView *)tableView{
    static NSString *ID = @"group_header_view";
    UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
    if(headerView == nil) {
        headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:ID];
    }
    return headerView;
}

// 重寫(xiě)方法,創(chuàng)建headerView時(shí)辜羊,同時(shí)添加自定義的按鈕和label踏兜。
- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier 
{
    if(self = [super initWithReuseIdentifier:reuseIdentifier]) {
        // 創(chuàng)建按鈕+label
        UIButton *btnGroupTitle = [[UIButton alloc] init];
        [self.contentView addSubview:btnGroupTitle];
        self.btnGroupTitle = btnGroupTitle;
        // 設(shè)置按鈕圖片(三角圖片,高亮背景圖)
        [btnGroupTitle setImage:[UIImage iamgeNamed:@"header_arrow"] forState:UIControlStateNormal];
        [btnGroupTitle setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        // 設(shè)置按鈕的點(diǎn)擊背景,2個(gè)模式Normal八秃,Highlighted
        // [btnGroupTitle setBackgroundImage: forState:];
        // 設(shè)置對(duì)齊方式, 間距
        btnGroupTitle.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        btnGroupTitle.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
        btnGroupTitle.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 0);

        // 添加點(diǎn)擊事件
        [btnGroupTitle addTarget:self action:@selector(btnGroupTitleClicked) forControlEvents:UIControlEventTouchUpInside];
        // 設(shè)置按鈕的顯示模式
        btnGroupTitle.imageView.contentMode = UIViewCOntentModeCenter;
        btnGroupTitle.imageView.clipsToBounds = NO; // 不截取多余部分碱妆。

        UILabel *lblCount = [[UILabel alloc] init]; // 好友數(shù)量顯示
        [self.contentView addSubview:lblCount];
        self.lblCount = lblCount;
    }
    return self;
}

// 組標(biāo)題按鈕的,點(diǎn)擊事件
- (void) btnGroupTitleClicked
{
    // 1.設(shè)置組的展開(kāi)昔驱、折疊狀態(tài)
    self.group.visible = !self.group.isVisible;
    // 添加代理方法山橄,讓控制器遵守寫(xiě),實(shí)現(xiàn)代理方法舍悯。
    // 10.3 使用代理,刷新TableView
    if([self.delegate respondsToSelector:@selector(groupHeaderViewDidClickClickTitleButton:)]) {
        // 調(diào)用代理方法,重新刷新
        [self.delegate groupHeaderViewDidClickClickTitleButton:self];
    }
}

// 當(dāng)1個(gè)新的headerView已經(jīng)加到某個(gè)父控件中的時(shí)候睡雇,執(zhí)行的回調(diào)方法萌衬。
// 處理三角形的旋轉(zhuǎn)。
- (void)didMoveToSuperview
{
    if(self.group.isVisible) {
        // 3.修改按鈕圖片它抱,讓按鈕旋轉(zhuǎn)90度秕豫。
        self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
    } else { // 旋轉(zhuǎn)回到原來(lái)的位置
        self.btnGroupTitle.imageView.transform = CGAffineTransformMakeRotation(0);
    }
}
@end

// 主控制器類(lèi),繼承自TableViewController

// CZQQFriendsTableViewController.h
@interface CZQQFriendsTableViewController
@end

//----------------------
#import "CZQQFriendsTableViewController.h"
// 類(lèi)拓展中观蓄,保存數(shù)據(jù)
@interface CZQQFriendsTableViewController () <CZGroupHeaderViewDelegate>
@property(nonatomic, strong) NSArray *groups;
@end

@implementation CZQQFriendsTableViewController
#pragma mark - ***懶加載數(shù)據(jù)***
- (NSArray *)groups
{
    if(_groups == nil) {
        NSSgring *path = [[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil];
        NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
        
        NSMutableArray *arrayModels = [NSMutableArray array];
        for(NSDictionary *dict in arrayDict) {
            CZGroup *model = [CZGroup groupWithDict:dict];
            [arrayModels addObject:model];
        }
        _group = arrayModels;
    }
    return _groups;
}

#pragma mark - ***實(shí)現(xiàn)CZGroupHeaderViewDelegate代理方法***
- (void)groupHeaderViewDidClickTitleButton:(CZGroupHeaderView *)groupHeaderView
{
    // 刷新tableView
    // [self.tableView reloadData];
    // 局部刷新混移,只刷新某個(gè)組。tag取到之前保存的組序號(hào)侮穿。
    NSIndexSet *idxSet = [NSIndexSet indexSetWithIndex:groupHeaderView.tag];
    [self.table reloadSections:idxSet withRowAnimation:UITableViewRowAnimationFade];
}

#pragma mark - ***實(shí)現(xiàn)數(shù)據(jù)源方法***
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return self.groups.count;
}
// self.group.visible = !self.group.isVisible;
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section
{
    CZGroup *group = self.groups[section];
    // 根據(jù)當(dāng)前組的狀態(tài)(是否展開(kāi))來(lái)設(shè)置不同的返回值歌径。
    if(self.group.isVisible) {
        return group.friends.count;
    }
    return 0;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 1. 獲取數(shù)據(jù)模型
    CZGroup *group = self.groups[indexPath.section];
    CZFriend *friend = group.friends[indexPath.row];
    
    // 2. 創(chuàng)建單元格。
    CZFriendCell *cell = [CZFriendCell friendCellWithTableView:tableView];
     
    // 3.設(shè)置單元格數(shù)據(jù)
    cell.friendModel = friend;
    return cell; // 4.返回單元格
}

// 設(shè)置組標(biāo)題:自定義
// - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
// {
//     CZGroup *group = self.groups[indexPath.section];
//     return group.name
// }

// UITableViewHeaderFooterView 具有重用功能亲茅。UIView不能重用回铛。
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{   // 1.獲取模型狗准;2.創(chuàng)建View;3.設(shè)置數(shù)據(jù)
    CZGroup *group = self.groups[section];
    CZGroupHeaderView *headerView = [CZGroupHeaderView  groupHeaderViewWithTableView:tableView];
    headerView.tag = section; // 記下當(dāng)前第幾組茵肃。
    headerView.group = group; // 設(shè)置數(shù)據(jù)
    // 剛創(chuàng)建好的headerView腔长,它的frame都是0,因?yàn)檫@個(gè)headerView验残,我們沒(méi)為其frame賦值捞附。所以frame都是0. 
    // 但是程序運(yùn)行后,看到的headerView是有frame的您没。原因:在當(dāng)前方法中鸟召,將headerView返回以后,UITableView在執(zhí)行的時(shí)候紊婉,會(huì)用到headerView药版。當(dāng)headerView被用到,就必須將headerView添加到TableView中喻犁。當(dāng)添加到TableView中的時(shí)候槽片,UITableView內(nèi)部會(huì)根據(jù)設(shè)置來(lái)動(dòng)態(tài)為headerView的frame賦值。
    // 也就是說(shuō)肢础,在TableView使用headerView的時(shí)候还栓,才會(huì)給headerView的frame賦值。

    // 10.4 設(shè)置完數(shù)據(jù)后传轰,設(shè)置代理剩盒。
    headerView.delegate = self;
    return headerView; // 4.返回view
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // 統(tǒng)一設(shè)置每組組標(biāo)題的高度
    self.tableView.sectionHeaderHeight = 44;
}
@end


2023/06/02 周五

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市慨蛙,隨后出現(xiàn)的幾起案子辽聊,更是在濱河造成了極大的恐慌,老刑警劉巖期贫,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跟匆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡通砍,警方通過(guò)查閱死者的電腦和手機(jī)玛臂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)封孙,“玉大人迹冤,你說(shuō)我怎么就攤上這事』⒓桑” “怎么了泡徙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)膜蠢。 經(jīng)常有香客問(wèn)我锋勺,道長(zhǎng)蚀瘸,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任庶橱,我火速辦了婚禮贮勃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘苏章。我一直安慰自己寂嘉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布枫绅。 她就那樣靜靜地躺著泉孩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪并淋。 梳的紋絲不亂的頭發(fā)上寓搬,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音县耽,去河邊找鬼句喷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛兔毙,可吹牛的內(nèi)容都是我干的唾琼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼澎剥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锡溯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起哑姚,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祭饭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后叙量,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體甜癞,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年宛乃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒸辆。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡征炼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躬贡,到底是詐尸還是另有隱情谆奥,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布拂玻,位于F島的核電站酸些,受9級(jí)特大地震影響宰译,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜魄懂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一沿侈、第九天 我趴在偏房一處隱蔽的房頂上張望市栗。 院中可真熱鬧蛛淋,春花似錦褐荷、人聲如沸叛甫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哲身。三九已至怔揩,卻和暖如春商膊,著一層夾襖步出監(jiān)牢的瞬間晕拆,已是汗流浹背吝镣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工凰锡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掂为,地道東北人昼扛。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓扰法,卻偏偏與公主長(zhǎng)得像塞颁,于是被迫代替她去往敵國(guó)和親酷窥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蓬推,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 中醫(yī)的魅力所在 “辯證論治”是中醫(yī)學(xué)的基本特點(diǎn)之一,是中醫(yī)診斷和治療疾病的基本原則,是中醫(yī)理蜕青、法右核、方、藥理論在臨床...
    手抖小知識(shí)白羊閱讀 65評(píng)論 0 0
  • 中醫(yī)的魅力所在 “辯證論治”是中醫(yī)學(xué)的基本特點(diǎn)之一染苛,是中醫(yī)診斷和治療疾病的基本原則茶行,是中醫(yī)理牧牢、法度陆、方懂傀、藥理論在臨床...
    帕金森大健康閱讀 40評(píng)論 0 0
  • 誠(chéng)惶誠(chéng)恐的早上,被自己的記憶愚弄了一番蜡感,給自己平靜的初夏清晨增添了一抹不一樣的色彩蹬蚁。 早上起床,和往常一樣...
    籬落易水閱讀 36評(píng)論 0 1
  • 額……老鐵們郑兴,我圖吧老撿垃圾的了犀斋,今天咱簡(jiǎn)單給各位表演一下兆芯C系列產(chǎn)品的整機(jī)頻率性能功耗測(cè)定,本篇是測(cè)試報(bào)告情连。 ...
    圖圖撿垃圾閱讀 129評(píng)論 0 0
  • 只要裝修就一定會(huì)產(chǎn)生甲醛污染叽粹,而這些甲醛除了裝修材料外,家具也是會(huì)造成甲醛超標(biāo)的重要原因,因此這就證明了挑選環(huán)保家...
    風(fēng)向生活閱讀 51評(píng)論 0 0