iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(二)

一、实现效果

           

二、实现代码

1.数据模型部分

TXFriendGroup.h文件

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface TXFriendGroup : NSObject
 4 @property (nonatomic, copy) NSString *name;
 5 /**
 6  *  数组中装的都是TXriend模型
 7  */
 8 @property (nonatomic, strong) NSArray *friends;
 9 @property (nonatomic, assign) int online;
10 
11 + (instancetype)groupWithDict:(NSDictionary *)dict;
12 - (instancetype)initWithDict:(NSDictionary *)dict;
13 @property (nonatomic, assign, getter = isOpened) BOOL opened;
14 
15 
16 @end

 

 TXFriendGroup.m文件

 1 //  Created by 鑫 on 14-10-13.
 2 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
 3 //
 4 
 5 #import "TXFriendGroup.h"
 6 #import "TXFriend.h"
 7 @implementation TXFriendGroup
 8 + (instancetype)groupWithDict:(NSDictionary *)dict
 9 {
10     return [[self alloc] initWithDict:dict];
11 }
12 
13 - (instancetype)initWithDict:(NSDictionary *)dict
14 {
15     if (self = [super init]) {
16         // 1.注入所有属性
17         [self setValuesForKeysWithDictionary:dict];
18         
19         // 2.特殊处理friends属性
20         NSMutableArray *friendArray = [NSMutableArray array];
21         for (NSDictionary *dict in self.friends) {
22             TXFriend *friend = [TXFriend friendWithDict:dict];
23             [friendArray addObject:friend];
24         }
25         self.friends = friendArray;
26     }
27     return self;
28 }
29 
30 @end

 

TXFriend.h文件

 1 #import <Foundation/Foundation.h>
 2 
 3 @interface TXFriend : NSObject
 4 @property (nonatomic, copy) NSString *name;
 5 @property (nonatomic, copy) NSString *icon;
 6 @property (nonatomic, copy) NSString *intro;
 7 @property (nonatomic, assign, getter = isVip) BOOL vip;
 8 
 9 + (instancetype)friendWithDict:(NSDictionary *)dict;
10 - (instancetype)initWithDict:(NSDictionary *)dict;
11 
12 @end

 

TXFriend.m文件

 1 #import "TXFriend.h"
 2 
 3 @implementation TXFriend
 4 + (instancetype)friendWithDict:(NSDictionary *)dict
 5 {
 6     return [[self alloc] initWithDict:dict];
 7 }
 8 
 9 - (instancetype)initWithDict:(NSDictionary *)dict
10 {
11     if (self = [super init]) {
12         [self setValuesForKeysWithDictionary:dict];
13     }
14     return self;
15 }
16 
17 @end

 

2.视图部分

TXFriendCell.h文件

1 #import <UIKit/UIKit.h>
2 @class TXFriend;
3 @interface TXFriendCell : UITableViewCell
4 + (instancetype)cellWithTableView:(UITableView *)tableView;
5 // friend是C++的关键字,不能用friend作为属性名
6 @property (nonatomic, strong) TXFriend *friendData;
7 @end

 

TXFriendCell.m文件

 1 #import "TXFriendCell.h"
 2 #import "TXFriend.h"
 3 @implementation TXFriendCell
 4 
 5 + (instancetype)cellWithTableView:(UITableView *)tableView
 6 {
 7     static NSString *ID = @"friend";
 8     TXFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
 9     if (cell == nil) {
10         cell = [[TXFriendCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
11     }
12     return cell;
13 }
14 
15 - (void)setFriendData:(TXFriend *)friendData
16 {
17     _friendData = friendData;
18     
19     self.imageView.image = [UIImage imageNamed:friendData.icon];
20     self.textLabel.text = friendData.name;
21     self.detailTextLabel.text = friendData.intro;
22 }
23 
24 @end

 

TXHeaderView.h文件

 1 //  TXHeaderView.h
 2 //  04-QQ好友列表
 3 //
 4 //  Created by 鑫 on 14-10-14.
 5 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
 6 //
 7 
 8 #import <UIKit/UIKit.h>
 9 @class TXFriendGroup, TXHeaderView;
10 //把自己的名字全进去TXHeaderView,告诉他那个家伙身上的按钮备点
11 
12 @protocol TXHeaderViewDelegate <NSObject>
13 @optional
14 - (void)headerViewDidClickedNameView:(TXHeaderView *)headerView;
15 @end
16 
17 @interface TXHeaderView : UITableViewHeaderFooterView
18 + (instancetype)headerViewWithTableView:(UITableView *)tableView;
19 
20 @property (nonatomic, strong) TXFriendGroup *group;
21 
22 @property (nonatomic, weak) id<TXHeaderViewDelegate> delegate;
23 @end

 

TXHeaderView.m文件

  1 #import "TXHeaderView.h"
  2 #import "TXFriendGroup.h"
  3 
  4 /**
  5  某个控件出不来:
  6  1.frame的尺寸和位置对不对
  7  
  8  2.hidden是否为YES
  9  
 10  3.有没有添加到父控件中
 11  
 12  4.alpha 是否 < 0.01
 13  
 14  5.被其他控件挡住了
 15  
 16  6.父控件的前面5个情况
 17  */
 18 
 19 @interface TXHeaderView()
 20 @property (nonatomic, weak) UILabel *countView;
 21 @property (nonatomic, weak) UIButton *nameView;
 22 @end
 23 
 24 @implementation TXHeaderView
 25 
 26 + (instancetype)headerViewWithTableView:(UITableView *)tableView
 27 {
 28     static NSString *ID = @"header";
 29     TXHeaderView *header = [tableView dequeueReusableHeaderFooterViewWithIdentifier:ID];
 30     if (header == nil) {
 31         header = [[TXHeaderView alloc] initWithReuseIdentifier:ID];
 32     }
 33     return header;
 34 }
 35 
 36 /**
 37  *  在这个初始化方法中,TXHeaderView的frame\bounds没有值
 38  */
 39 - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier
 40 {
 41     if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
 42         // 添加子控件
 43         // 1.添加按钮
 44         UIButton *nameView = [UIButton buttonWithType:UIButtonTypeCustom];
 45         // 背景图片
 46         [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg"] forState:UIControlStateNormal];
 47         [nameView setBackgroundImage:[UIImage imageNamed:@"buddy_header_bg_highlighted"] forState:UIControlStateHighlighted];
 48         // 设置按钮内部的左边箭头图片
 49         [nameView setImage:[UIImage imageNamed:@"buddy_header_arrow"] forState:UIControlStateNormal];
 50         [nameView setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
 51         // 设置按钮的内容左对齐
 52         nameView.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
 53         // 设置按钮的内边距
 54         //        nameView.imageEdgeInsets
 55         nameView.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
 56         nameView.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
 57         [nameView addTarget:self action:@selector(nameViewClick) forControlEvents:UIControlEventTouchUpInside];
 58         
 59         // 设置按钮内部的imageView的内容模式为居中
 60         nameView.imageView.contentMode = UIViewContentModeCenter;
 61         // 超出边框的内容不需要裁剪
 62         nameView.imageView.clipsToBounds = NO;
 63         
 64         [self.contentView addSubview:nameView];
 65         self.nameView = nameView;
 66         
 67         // 2.添加好友数
 68         UILabel *countView = [[UILabel alloc] init];
 69         countView.textAlignment = NSTextAlignmentRight;
 70         countView.textColor = [UIColor grayColor];
 71         [self.contentView addSubview:countView];
 72         self.countView = countView;
 73     }
 74     return self;
 75 }
 76 
 77 /**
 78  *  当一个控件的frame发生改变的时候就会调用
 79  *
 80  *  一般在这里布局内部的子控件(设置子控件的frame)
 81  */
 82 - (void)layoutSubviews
 83 {
 84 #warning 一定要调用super的方法
 85     [super layoutSubviews];
 86     
 87     // 1.设置按钮的frame
 88     self.nameView.frame = self.bounds;
 89     
 90     // 2.设置好友数的frame
 91     CGFloat countY = 0;
 92     CGFloat countH = self.frame.size.height;
 93     CGFloat countW = 150;
 94     CGFloat countX = self.frame.size.width - 10 - countW;
 95     self.countView.frame = CGRectMake(countX, countY, countW, countH);
 96 }
 97 
 98 - (void)setGroup:(TXFriendGroup *)group
 99 {
100     _group = group;
101     
102     // 1.设置按钮文字(组名)
103     [self.nameView setTitle:group.name forState:UIControlStateNormal];
104     
105     // 2.设置好友数(在线数/总数)
106     self.countView.text = [NSString stringWithFormat:@"%d/%d", group.online, group.friends.count];
107 }
108 
109 /**
110  *  监听组名按钮的点击
111  */
112 - (void)nameViewClick
113 {
114     // 1.修改组模型的标记(状态取反)
115     self.group.opened = !self.group.isOpened;
116     
117     // 2.刷新表格
118     if ([self.delegate respondsToSelector:@selector(headerViewDidClickedNameView:)]) {
119         [self.delegate headerViewDidClickedNameView:self];
120     }
121 }
122 
123 /**
124  *  当一个控件被添加到父控件中就会调用
125  */
126 - (void)didMoveToSuperview
127 {
128     if (self.group.opened) {
129         self.nameView.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);
130     } else {
131         self.nameView.imageView.transform = CGAffineTransformMakeRotation(0);
132     }
133 }
134 
135 /**
136  *  当一个控件即将被添加到父控件中会调用
137  */
138 //- (void)willMoveToSuperview:(UIView *)newSuperview
139 //{
140 //
141 //}
142 @end

 

3.控制器部分

TXViewController.h文件

 1 //  TXViewController.h
 2 //  04-QQ好友列表
 3 //
 4 //  Created by 鑫 on 14-10-13.
 5 //  Copyright (c) 2014年 梁镋鑫. All rights reserved.
 6 //
 7 
 8 #import <UIKit/UIKit.h>
 9 
10 @interface TXViewController : UITableViewController
11 
12 @end

 

TXViewController.m文件

 1 #import "TXViewController.h"
 2 #import "TXFriendGroup.h"
 3 #import "TXFriend.h"
 4 #import "TXHeaderView.h"
 5 #import "TXFriendCell.h"
 6 
 7 @interface TXViewController () <TXHeaderViewDelegate>
 8 @property (nonatomic, strong) NSArray *groups;
 9 @end
10 
11 @implementation TXViewController
12 
13 - (void)viewDidLoad
14 {
15     [super viewDidLoad];
16     
17     // 每一行cell的高度
18     self.tableView.rowHeight = 50;
19     // 每一组头部控件的高度
20     self.tableView.sectionHeaderHeight = 44;
21 }
22 
23 - (NSArray *)groups
24 {
25     if (_groups == nil) {
26         NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"friends.plist" ofType:nil]];
27         
28         NSMutableArray *groupArray = [NSMutableArray array];
29         for (NSDictionary *dict in dictArray) {
30             TXFriendGroup *group = [TXFriendGroup groupWithDict:dict];
31             [groupArray addObject:group];
32         }
33         
34         _groups = groupArray;
35     }
36     return _groups;
37 }
38 
39 - (BOOL)prefersStatusBarHidden
40 {
41     return YES;
42 }
43 
44 #pragma mark - 数据源方法
45 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
46 {
47     return self.groups.count;
48 }
49 
50 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
51 {
52     TXFriendGroup *group = self.groups[section];
53     
54     return (group.isOpened ? group.friends.count : 0);
55 }
56 
57 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
58 {
59     // 1.创建cell
60     TXFriendCell *cell = [TXFriendCell cellWithTableView:tableView];
61     
62     // 2.设置cell的数据
63     TXFriendGroup *group = self.groups[indexPath.section];
64     cell.friendData = group.friends[indexPath.row];
65     
66     return cell;
67 }
68 
69 /**
70  *  返回每一组需要显示的头部标题(字符出纳)
71  */
72 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
73 {
74     // 1.创建头部控件
75     TXHeaderView *header = [TXHeaderView headerViewWithTableView:tableView];
76     header.delegate = self;
77     
78     // 2.给header设置数据(给header传递模型)
79     header.group = self.groups[section];
80     
81     return header;
82 }
83 
84 #pragma mark - headerView的代理方法
85 /**
86  *  点击了headerView上面的名字按钮时就会调用
87  */
88 - (void)headerViewDidClickedNameView:(TXHeaderView *)headerView
89 {
90     [self.tableView reloadData];
91 }
92 @end

 

三、代码说明

1.项目文件结构

2.注意点

(1)调整字体的大小:    self.textLabel.font=[UIFont systemFontOfSize:15.f];

(2)-(void)layoutSubviews方法。该方法在控件的frame被改变的时候就会调用,这个方法一般用于调整子控件的位置,注意一定要调用[super layoutSubviews];

(3)但凡在init方法中获取到的frame都是0;

(4)如果控件不显示,有以下一些排错方法

a.frame为空(没有设置frame)
b.hidden是否为YES
c.alpha<=0.1(透明度)
d.没有添加到父控件中
e.查看父控件以上几点

(5)请注意在设置按钮的文本时,一定要设置按钮的状态

正确:[self.btn setTitle:_group.name forState:UIControlStateNormal];
错误: self.btn.titleLabel.text=_group.name;

(6)调用构造方法时,一定要先初始化父类的方法,先判断,再进行自己属性的初始化

self=[super initWithReuseIdentifier:reuseIdentifier]
if(self)
{
……
}
(7)当一个控件被添加到其它视图上的时候会调用以下方法

1) 已经被添加到父视图上的时候会调用- (void)didMoveToSuperview

2) 即将被添加到父视图上的时候会调用- (void)willMoveToSuperview:(UIView *)newSuperview

(8)图片填充知识

   1)设置btn中的图片不填充整个imageview btn.imageView.contentMode = UIViewContentModeCenter;

   2)超出范围的图片不要剪切

  //btn.imageView.clipsToBounds = NO;

  btn.imageView.layer.masksToBounds = NO;

四、补充(代理)

设置代理的几个步骤
(1)如果一个视图中的某个按钮被点击了,这个时候需要去主控制器中刷新数据。有一种做法是,让这个视图拥有控制器这个属性,然后当按钮被点击的时候去利用该属性去做刷新数据的操作。另一种做法是把控制器设置为这个视图的代理,当视图中的某个按钮被点击的时候,通知它的代理(主控制器)去干刷新数据这件事。
(2)要成为代理是由条件的,有以下几个步骤
    1).双方约定一个协议(代理协议,注意命名规范),在视图中自定义一个协议,协议中提供一个方法。

      @protocol YYHeaderViewDelegate <NSObject>

      -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView;

      @end

    2).在视图中添加一个id类型的属性变量,任何人只要遵守了约定协议的都可以成为它的代理。

      //delegate遵守YYHeaderViewDelegate这个协议,可以使用协议中的方法

      @property(nonatomic,weak)id<YYHeaderViewDelegate> delegate;

    3).在控制器中,遵守自定义的代理协议,就可以使用代理提供的方法,在这个方法中对数据进行刷新。

      @interface YYViewController ()<YYHeaderViewDelegate>

      -(void)headerViewDidClickHeaderView:(YYHeaderView *)headerView

        {

              [self.tableView reloadData];

        }

    4).把控制器设置作为按钮点击事件的代理。

        headerview.delegate=self;

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。