學習目標
1.【掌握】靜態單元格應用
2.【掌握】動態原型應用
3.【理解】UITableViewHeaderFooterView
一、靜態單元格應用
這個案例的目的是了解靜態單元格的使用場合及操作方式,在一些情況下使用靜態單元格會更加方便和快捷。我們需要了解靜態單元格的一些特性及設置方式。案例效果圖如下:
靜態單元格只支持UITableViewController,所以先將之前的viewController刪除。拖入UITableViewController,設置Size屬性。再選擇UITableView並設置屬性Content屬性為Static Cells:
Dynamin ProtoTypes:動態單元格,通過代碼進行設置
Static Cells:靜態單元格,通過界面進行設置,固定的。
設置每一組cell的數量:默認每一組有三個cell,修改每一組cell的數量。
設置cell的高度:Cell的高度也就是tableview的row height屬性。
設置cell的顯示樣式:這里的樣式和代碼創建cell的系統提供的樣式類似,不過多了一個Custom自定義。
設置cell的圖片:給Cell設置圖片,也就是Cell的image屬性賦值。
設置cell的文本:
完成上面的操作后我們可以添加任意組(sections),設置對應組的行數(rows)。
需要注意的是,當我們刪除原有控制器,創建新控制器后需要將新控制器設為初始顯示的控制器。也就是勾選Is Initial View Controller,否則啟動模擬器看不到界面。如下圖所示:
二、動態原型應用
上面演示了靜態單元格的使用,下面接着演示動態原型的使用,也就是UITableView的Content屬性中的Dynamic protoTypes。設置這個屬性后,我們可以通過代碼根據原型動態創建Cell。下面來看看一個應用管理的案例,案例效果圖如下:
首先,創建項目,導入素材圖片和plist文件。
創建模型類,加載plist文件中的數據封裝模型,並返回模型數組。
JFApp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#import <Foundation/Foundation.h>
@interface
JFApp
: NSObject
@property
(
copy
,
nonatomic
)
NSString
*size
;
@property
(
copy
,
nonatomic
)
NSString
*download
;
@property
(
copy
,
nonatomic
)
NSString
*name
;
@property
(
copy
,
nonatomic
)
NSString
*icon
;
//快速創建模型
-
(
instancetype
)
initWithDictionary
:
(
NSDictionary
*
)
dict
;
+
(
instancetype
)
appWithDictionary
:
(
NSDictionary
*
)
dict
;
//返回模型數組
+
(
NSArray
*
)
apps
;
@end
|
JFApp.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#import "JFApp.h"
@implementation
JFApp
//快速創建模型
-
(
instancetype
)
initWithDictionary
:
(
NSDictionary
*
)
dict
{
if
(
self
=
[
super
init
]
)
{
[
self
setValuesForKeysWithDictionary
:dict
]
;
}
return
self
;
}
+
(
instancetype
)
appWithDictionary
:
(
NSDictionary
*
)
dict
{
return
[
[
self
alloc
]
initWithDictionary
:dict
]
;
}
//返回模型數組
+
(
NSArray
*
)
apps
{
NSArray
*array
=
[
NSArray
arrayWithContentsOfFile
:
[
[
NSBundle
mainBundle
]
pathForResource
:
@"apps_full.plist"
ofType
:nil
]
]
;
NSMutableArray
*arrayM
=
[
NSMutableArray
array
]
;
for
(
NSDictionary
*dict
in
array
)
{
JFApp
*app
=
[
JFApp
appWithDictionary
:dict
]
;
[
arrayM
addObject
:app
]
;
}
return
arrayM
;
}
@end
|
在Main.storyboard中修改size為4.7,拖入一個全屏的UITableView控件,再拖入一個UITableViewCell 控件到UITableView中,並拖入Cell的子控件。Cell的高度也就是tableview的rowheight屬性,tableview的 content屬性默認就是Dynamic prototypes(動態原型),所以無需更改。
創建Cell封裝類,並指定Cell的Class屬性為我們創建的封裝類JFAppCell。
指定Class后即可進行屬性連線,一般屬性連線我們都封裝在類擴展(匿名分類,也叫延展)里,而不是.h文件中。
設置Cell的重用標識符(Identifier), 並在類中定義一個模型屬性和快速創建Cell的方法並實現。點擊下載按鈕后,會彈出一個提示,彈出的提示不會跟隨tableview滾動,所以需要添加這 個提示View到tableview的父視圖中。這樣就必須訪問控制器,所以我們使用代理來完成這個操作,讓控制器成為代理對象,替Cell完成點擊事 件。
JFAppCell.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#import <UIKit/UIKit.h>
@class
JFApp
;
@class
JFAppCell
;
//定義一個代理
@protocol
JFAppCellDelegate
<NSObject>
@
required
-
(
void
)
downloadButtonDidClick
:
(
JFAppCell
*
)
appCell
;
@end
@interface
JFAppCell
: UITableViewCell
//為子控件賦值的模型屬性
@property
(
strong
,
nonatomic
)
JFApp
*app
;
//代理屬性
@property
(
weak
,
nonatomic
)
id
<JFAppCellDelegate>
delegate
;
//快速創建cell的方法
+
(
instancetype
)
appCellWithDictionary
:
(
UITableView
*
)
tableView
;
@end
|
JFAppCell.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#import "JFAppCell.h"
#import "JFApp.h"
@interface
JFAppCell
(
)
@property
(
weak
,
nonatomic
)
IBOutlet
UIImageView
*iconView
;
@property
(
weak
,
nonatomic
)
IBOutlet
UILabel
*nameView
;
@property
(
weak
,
nonatomic
)
IBOutlet
UILabel
*messageView
;
@property
(
weak
,
nonatomic
)
IBOutlet
UIButton
*downloadView
;
//下載按鈕的點擊事件
-
(
IBAction
)
downloadButtonDidClick
;
@end
@implementation
JFAppCell
//下載按鈕的點擊事件
-
(
IBAction
)
downloadButtonDidClick
{
//點擊下載按鈕后禁用下載按鈕
self
.
downloadView
.
enabled
=
NO
;
//彈出下載信息,彈出View是添加View到Tableview的父容器中,這里無法訪問到。所以得用代理
if
(
[
self
.
delegate
respondsToSelector
:
@selector
(
downloadButtonDidClick
:
)
]
)
{
[
self
.
delegate
downloadButtonDidClick
:self
]
;
}
}
//快速創建cell的方法
+
(
instancetype
)
appCellWithDictionary
:
(
UITableView
*
)
tableView
{
//用cell重用標識符創建cell,這一步前必須在Cell中設置他的Identifier屬性
JFAppCell
*cell
=
[
tableView
dequeueReusableCellWithIdentifier
:
@"app"
]
;
return
cell
;
}
//重寫set方法為Cell的子控件賦值
-
(
void
)
setApp
:
(
JFApp
*
)
app
{
_app
=
app
;
//圖標
self
.
iconView
.
image
=
[
UIImage
imageNamed
:app
.
icon
]
;
//名稱
self
.
nameView
.
text
=
app
.
name
;
//下載信息
self
.
messageView
.
text
=
[
NSString
stringWithFormat
:
@"大小:%@M | 下載量:%@萬"
,
app
.
size
,
app
.
download
]
;
}
@end
|
在控制器對tableview進行控件連線,然后懶加載模型數組,並實現數據源方法和Cell的代理方法。最終實現我們的需求,具體控制器中的代碼如下:
ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
#import "ViewController.h"
#import "JFApp.h"
#import "JFAppCell.h"
@interface
ViewController
(
)
<
UITableViewDataSource
,
JFAppCellDelegate
>
@property
(
weak
,
nonatomic
)
IBOutlet
UITableView
*tableView
;
@property
(
strong
,
nonatomic
)
NSArray
*apps
;
@end
@implementation
ViewController
//隱藏頂部狀態欄
-
(
BOOL
)
prefersStatusBarHidden
{
return
YES
;
}
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
]
;
self
.
tableView
.
dataSource
=
self
;
}
//懶加載
-
(
NSArray
*
)
apps
{
if
(
_apps
==
nil
)
{
_apps
=
[
JFApp
apps
]
;
}
return
_apps
;
}
//每組一共有多少行數據
-
(
NSInteger
)
tableView
:
(
UITableView
*
)
tableView
numberOfRowsInSection
:
(
NSInteger
)
section
{
return
self
.
apps
.
count
;
}
//創建cell
-
(
UITableViewCell
*
)
tableView
:
(
UITableView
*
)
tableView
cellForRowAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
//獲取當前數據模型
JFApp
*app
=
self
.
apps
[
indexPath
.
row
]
;
//創建cell
JFAppCell
*cell
=
[
JFAppCell
appCellWithDictionary
:tableView
]
;
//指定Cell的代理對象
cell
.
delegate
=
self
;
//為Cell賦值
cell
.
app
=
app
;
return
cell
;
}
//實現Cell的代理方法,在下載按鈕被點擊后觸發
-
(
void
)
downloadButtonDidClick
:
(
JFAppCell
*
)
appCell
{
//創建提示Label
UILabel
*downMessage
=
[
[
UILabel
alloc
]
init
]
;
//計算並設置frame
CGFloat
downW
=
200
;
CGFloat
downH
=
20
;
CGFloat
downX
=
(
self
.
view
.
frame
.
size
.
width
-
downW
)
/
2
;
CGFloat
downY
=
(
self
.
view
.
frame
.
size
.
height
-
downH
)
/
2
;
downMessage
.
frame
=
CGRectMake
(
downX
,
downY
,
downW
,
downH
)
;
//設置一些屬性
downMessage
.
text
=
[
NSString
stringWithFormat
:
@"%@正在下載..."
,
appCell
.
app
.
name
]
;
downMessage
.
backgroundColor
=
[
UIColor
grayColor
]
;
downMessage
.
textAlignment
=
NSTextAlignmentCenter
;
downMessage
.
alpha
=
0
;
//添加到self.view中
[
self
.
view
addSubview
:downMessage
]
;
//以動畫形式彈出提示並隱藏,最終移除
[
UIView
animateWithDuration
:
1
animations
:
^
{
downMessage
.
alpha
=
0.7
;
}
completion
:
^
(
BOOL
finished
)
{
dispatch_after
(
dispatch_time
(
DISPATCH_TIME_NOW
,
(
int64_t
)
(
1
*
NSEC_PER_SEC
)
)
,
dispatch_get_main_queue
(
)
,
^
{
[
UIView
animateWithDuration
:
1
animations
:
^
{
downMessage
.
alpha
=
0
;
}
completion
:
^
(
BOOL
finished
)
{
[
downMessage
removeFromSuperview
]
;
}
]
;
}
)
;
}
]
;
}
@end
|
三、UITableViewHeaderFooterView
UITableViewHeaderFooterView是一個定義列表頭部視圖、列表尾部視圖的類,HeaderFooterView一般是用在列表的頭部,顯示不同的分組狀態信息。我們通過QQ分組來演示自定義HeaderFooterView的方法,下面是完成后的效果圖:
導入素材和plist文件,從下圖可以看出,我們需要創建嵌套模型,也就是每一個組好友和每一個好友都需要封裝模型。
先封裝單個好友模型,是否是vip定義為BOOL類型。
JFFriend.h
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#import <Foundation/Foundation.h>
@interface
JFFriend
: NSObject
@property
(
copy
,
nonatomic
)
NSString
*icon
;
@property
(
copy
,
nonatomic
)
NSString
*intro
;
@property
(
copy
,
nonatomic
)
NSString
*name
;
@property
(
assign
,
nonatomic
,
getter
=
isVip
)
BOOL
vip
;
//快速創建模型數組
-
(
instancetype
)
initWithDictionary
:
(
NSDictionary
*
)
dict
;
+
(
instancetype
)
friendWithDictionary
:
(
NSDictionary
*
)
dict
;
@end
|
JFFriend.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#import "JFFriend.h"
@implementation
JFFriend
//快速創建模型數組
-
(
instancetype
)
initWithDictionary
:
(
NSDictionary
*
)
dict
{
if
(
self
=
[
super
init
]
)
{
[
self
setValuesForKeysWithDictionary
:dict
]
;
}
return
self
;
}
+
(
instancetype
)
friendWithDictionary
:
(
NSDictionary
*
)
dict
{
return
[
[
self
alloc
]
initWithDictionary
:dict
]
;
}
@end
|
然后再封裝一組好友的模型,因為好友分組是有收起、展開兩種狀態的,所以定義一個BOOL類型來存儲好友組的狀態。
JFFriendGroup.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#import <Foundation/Foundation.h>
@interface
JFFriendGroup
: NSObject
@property
(
strong
,
nonatomic
)
NSArray
*friends
;
@property
(
copy
,
nonatomic
)
NSString
*name
;
@property
(
assign
,
nonatomic
)
int
online
;
//是否陳列出好友列表,默認不陳列
@property
(
assign
,
nonatomic
,
getter
=
isDisplay
)
BOOL
display
;
//快速創建組模型
-
(
instancetype
)
initWithDictionary
:
(
NSDictionary
*
)
dict
;
+
(
instancetype
)
friendGroupWithDictionary
:
(
NSDictionary
*
)
dict
;
//返回組模型數組
+
(
NSArray
*
)
friendGroups
;
@end
|
JFFriendGroup.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
#import "JFFriendGroup.h"
#import "JFFriend.h"
@implementation
JFFriendGroup
//快速創建組模型
-
(
instancetype
)
initWithDictionary
:
(
NSDictionary
*
)
dict
{
if
(
self
=
[
super
init
]
)
{
[
self
setValuesForKeysWithDictionary
:dict
]
;
//這樣賦值后friends數組中是字典,需要轉模型
NSMutableArray
*arrayM_temp
=
[
NSMutableArray
array
]
;
for
(
NSDictionary
*dict_temp
in
self
.
friends
)
{
JFFriend
*myFriend
=
[
JFFriend
friendWithDictionary
:dict_temp
]
;
[
arrayM
_
temp
addObject
:myFriend
]
;
}
self
.
friends
=
arrayM_temp
;
}
return
self
;
}
+
(
instancetype
)
friendGroupWithDictionary
:
(
NSDictionary
*
)
dict
{
return
[
[
self
alloc
]
initWithDictionary
:dict
]
;
}
//返回組模型數組
+
(
NSArray
*
)
friendGroups
{
NSArray
*array
=
[
NSArray
arrayWithContentsOfFile
:
[
[
NSBundle
mainBundle
]
pathForResource
:
@"friends.plist"
ofType
:nil
]
]
;
NSMutableArray
*arrayM
=
[
NSMutableArray
array
]
;
for
(
NSDictionary
*dict
in
array
)
{
JFFriendGroup
*friendGroup
=
[
JFFriendGroup
friendGroupWithDictionary
:dict
]
;
[
arrayM
addObject
:friendGroup
]
;
}
return
arrayM
;
}
@end
|
封裝Cell類,這里的Cell是指好友而不是分組。也就是每一個Cell顯示一個好友的信息,所以我們定義的模型屬性是好友模型而不是好友分組模型。並且這里使用系統提供的Cell樣式已經能夠滿足我們的需求,所以無需再手動創建。具體Cell類代碼入下:
JFFriendCell.h
1
2
3
4
5
6
7
8
9
10
|
#import <UIKit/UIKit.h>
@class
JFFriend
;
@interface
JFFriendCell
: UITableViewCell
@property
(
strong
,
nonatomic
)
JFFriend
*myFriend
;
//快速創建cell
+
(
instancetype
)
friendCellWithTableView
:
(
UITableView
*
)
tableView
;
@end
|
JFFriendCell.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#import "JFFriendCell.h"
#import "JFFriend.h"
@implementation
JFFriendCell
//快速創建cell
+
(
instancetype
)
friendCellWithTableView
:
(
UITableView
*
)
tableView
{
static
NSString
*ID
=
@"myFriend"
;
//從緩存中創建Cell
JFFriendCell
*cell
=
[
tableView
dequeueReusableCellWithIdentifier
:ID
]
;
if
(
cell
==
nil
)
{
//系統自帶的樣式已經能夠滿足我們的需求,所以無需手動創建,直接使用合適系統提供的cell樣式
cell
=
[
[
JFFriendCell
alloc
]
initWithStyle
:UITableViewCellStyleSubtitle
reuseIdentifier
:ID
]
;
}
return
cell
;
}
//重寫set方法為Cell賦值
-
(
void
)
setMyFriend
:
(
JFFriend
*
)
myFriend
{
_myFriend
=
myFriend
;
//為Cell賦值
self
.
imageView
.
image
=
[
UIImage
imageNamed
:myFriend
.
icon
]
;
self
.
textLabel
.
text
=
myFriend
.
name
;
self
.
detailTextLabel
.
text
=
myFriend
.
intro
;
//如果是vip則昵稱是紅色
if
(
myFriend
.
isVip
)
{
self
.
textLabel
.
textColor
=
[
UIColor
redColor
]
;
}
}
@end
|
封裝好模型和Cell后我們就可以在控制器進行調用了,先顯示出數據,再根據我們的需求進行修改。我們的QQ列表整個都是tableview,所以不用使用ViewController,直接使用TableviewController。在Main.storyboard中刪除原有的ViewController拖入一個TableviewController。
然后再修改ViewController.h的繼承父類為UITableViewController,才能設置新的控制器所屬Class為這個類。
1
2
3
4
5
|
#import <UIKit/UIKit.h>
//修改繼承的父類為UITableViewController
@interface
ViewController
: UITableViewController
@end
|
設置UITableViewController的Class屬性為ViewController,我們也可以新創建一個類繼承自UITableViewController,然后在這里設置Class為我們新創建的那個類。
在控制器中懶加載數據,實現數據源方法顯示出數據。因為我們Main.storyboard中使用的是TableViewController,所以無需手動遵守數據源、代理協議和手動指定數據源對象、代理對象。
ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#import "ViewController.h"
#import "JFFriendGroup.h"
#import "JFFriendCell.h"
#import "JFFriend.h"
@interface
ViewController
(
)
@property
(
strong
,
nonatomic
)
NSArray
*friendGroups
;
@end
@implementation
ViewController
//隱藏狀態欄
-
(
BOOL
)
prefersStatusBarHidden
{
return
YES
;
}
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
]
;
}
//懶加載
-
(
NSArray
*
)
friendGroups
{
if
(
_friendGroups
==
nil
)
{
_friendGroups
=
[
JFFriendGroup
friendGroups
]
;
}
return
_friendGroups
;
}
//一共多少組,每一個小組就是一組
-
(
NSInteger
)
numberOfSectionsInTableView
:
(
UITableView
*
)
tableView
{
return
self
.
friendGroups
.
count
;
}
//每組多少行
-
(
NSInteger
)
tableView
:
(
UITableView
*
)
tableView
numberOfRowsInSection
:
(
NSInteger
)
section
{
//獲取組模型
JFFriendGroup
*friendGroup
=
self
.
friendGroups
[
section
]
;
return
friendGroup
.
friends
.
count
;
}
//創建Cell
-
(
UITableViewCell
*
)
tableView
:
(
UITableView
*
)
tableView
cellForRowAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
//獲取組模型
JFFriendGroup
*friendGroup
=
self
.
friendGroups
[
indexPath
.
section
]
;
//獲取單個好友模型
JFFriend
*myFriend
=
friendGroup
.
friends
[
indexPath
.
row
]
;
//創建cell
JFFriendCell
*cell
=
[
JFFriendCell
friendCellWithTableView
:tableView
]
;
//為Cell賦值
cell
.
myFriend
=
myFriend
;
return
cell
;
}
@end
|
完成后的效果為:
數據已經顯示出來了,但是沒有進行分組。如果我們使用系統自帶的分組樣式,是無法滿足需求的。比如整個分組頭部可以點擊,並且帶小圖標,說明這整個分組頭部是一個按鈕,並且按鈕上還有一個Label用來顯示在線人數。
下面開始自定義ViewHeaderFooterView,創建一個類並繼承自UITableViewHeaderFooterView類。headerView點擊后會展開列表,也就是會刷新tableview,這個操作在headerView中是無法完成的(不能將控制器做參數傳遞)。所以我們通過代理來完成,讓控制器成為headerView的代理對象,並實現對應的代理方法來完成這個需求。
JFHeaderView.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#import <UIKit/UIKit.h>
@class
JFFriendGroup
;
@class
JFHeaderView
;
@protocol
JFHeaderViewDelegate
<NSObject>
-
(
void
)
headerViewButtonDidClick
:
(
JFHeaderView
*
)
headerView
;
@end
@interface
JFHeaderView
: UITableViewHeaderFooterView
//返回一個headerView
+
(
instancetype
)
headerViewWithTableView
:
(
UITableView
*
)
tableView
;
@property
(
strong
,
nonatomic
)
JFFriendGroup
*friendGroup
;
//headerView的代理屬性
@property
(
weak
,
nonatomic
)
id
<JFHeaderViewDelegate>
delegate
;
@end
|
JFHeaderView.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#import "JFHeaderView.h"
#import "JFFriendGroup.h"
@interface
JFHeaderView
(
)
@property
(
weak
,
nonatomic
)
UIButton
*btn
;
//headerView按鈕
@property
(
weak
,
nonatomic
)
UILabel
*lbl
;
//在線人數
@end
@implementation
JFHeaderView
//返回一個headerView
+
(
instancetype
)
headerViewWithTableView
:
(
UITableView
*
)
tableView
{
static
NSString
*headerID
=
@"header"
;
JFHeaderView
*headerView
=
[
tableView
dequeueReusableHeaderFooterViewWithIdentifier
:headerID
]
;
if
(
headerView
==
nil
)
{
headerView
=
[
[
JFHeaderView
alloc
]
initWithReuseIdentifier
:headerID
]
;
}
return
headerView
;
}
//重寫initWithReuseIdentifier:方法創建自定義headerView
-
(
instancetype
)
initWithReuseIdentifier
:
(
NSString
*
)
reuseIdentifier
{
if
(
self
=
[
super
initWithReuseIdentifier
:reuseIdentifier
]
)
{
UIButton
*btn
=
[
[
UIButton
alloc
]
init
]
;
[
btn
setBackgroundImage
:
[
UIImage
imageNamed
:
@"buddy_header_bg"
]
forState
:UIControlStateNormal
]
;
[
btn
setBackgroundImage
:
[
UIImage
imageNamed
:
@"buddy_header_bg_highlighted"
]
forState
:UIControlStateHighlighted
]
;
[
btn
setImage
:
[
UIImage
imageNamed
:
@"buddy_header_arrow"
]
forState
:UIControlStateNormal
]
;
btn
.
contentHorizontalAlignment
=
UIControlContentHorizontalAlignmentLeft
;
btn
.
contentEdgeInsets
=
UIEdgeInsetsMake
(
0
,
10
,
0
,
0
)
;
btn
.
titleEdgeInsets
=
UIEdgeInsetsMake
(
0
,
10
,
0
,
0
)
;
[
btn
setTitleColor
:
[
UIColor
blackColor
]
forState
:UIControlStateNormal
]
;
btn
.
imageView
.
contentMode
=
UIViewContentModeCenter
;
btn
.
imageView
.
clipsToBounds
=
NO
;
//添加到headerView
[
self
addSubview
:btn
]
;
self
.
btn
=
btn
;
[
self
.
btn
addTarget
:self
action
:
@selector
(
headerViewButtonDidClick
)
forControlEvents
:UIControlEventTouchUpInside
]
;
UILabel
*lbl
=
[
[
UILabel
alloc
]
init
]
;
//文本右對齊
lbl
.
textAlignment
=
NSTextAlignmentRight
;
[
self
addSubview
:lbl
]
;
self
.
lbl
=
lbl
;
}
return
self
;
}
//按鈕單擊事件
-
(
void
)
headerViewButtonDidClick
{
self
.
friendGroup
.
display
=
!
self
.
friendGroup
.
isDisplay
;
if
(
[
self
.
delegate
respondsToSelector
:
@selector
(
headerViewButtonDidClick
:
)
]
)
{
[
self
.
delegate
headerViewButtonDidClick
:self
]
;
}
}
//當一個新的headerView已經添加到某個父控件中的時候調用這個方法
-
(
void
)
didMoveToSuperview
{
if
(
self
.
friendGroup
.
isDisplay
)
{
self
.
btn
.
imageView
.
transform
=
CGAffineTransformMakeRotation
(
M_PI_2
)
;
}
else
{
self
.
btn
.
imageView
.
transform
=
CGAffineTransformMakeRotation
(
0
)
;
}
}
//重寫set方法為headerView賦值
-
(
void
)
setFriendGroup
:
(
JFFriendGroup
*
)
friendGroup
{
_friendGroup
=
friendGroup
;
//設置組名
[
self
.
btn
setTitle
:friendGroup
.
name
forState
:UIControlStateNormal
]
;
//設置在線人數
self
.
lbl
.
text
=
[
NSString
stringWithFormat
:
@"%d / %lu"
,
friendGroup
.
online
,
friendGroup
.
friends
.
count
]
;
}
//當將這個控件真正添加到父控件的時候,會調用這個方法設置當前控件的所有子控件的frame
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
]
;
self
.
btn
.
frame
=
CGRectMake
(
0
,
0
,
self
.
frame
.
size
.
width
,
self
.
frame
.
size
.
height
)
;
self
.
lbl
.
frame
=
CGRectMake
(
300
,
0
,
60
,
44
)
;
}
@end
|
在控制器中遵守JFHeaderViewDelegate代理協議並實現代理方法,實現單組數據刷新。
ViewController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
#import "ViewController.h"
#import "JFFriendGroup.h"
#import "JFFriendCell.h"
#import "JFFriend.h"
#import "JFHeaderView.h"
@interface
ViewController
(
)
<JFHeaderViewDelegate>
@property
(
strong
,
nonatomic
)
NSArray
*friendGroups
;
@end
@implementation
ViewController
//隱藏狀態欄
-
(
BOOL
)
prefersStatusBarHidden
{
return
YES
;
}
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
]
;
//設置headerView的高度
self
.
tableView
.
sectionHeaderHeight
=
50
;
}
//懶加載
-
(
NSArray
*
)
friendGroups
{
if
(
_friendGroups
==
nil
)
{
_friendGroups
=
[
JFFriendGroup
friendGroups
]
;
}
return
_friendGroups
;
}
//一共多少組,每一個小組就是一組
-
(
NSInteger
)
numberOfSectionsInTableView
:
(
UITableView
*
)
tableView
{
return
self
.
friendGroups
.
count
;
}
//每組多少行
-
(
NSInteger
)
tableView
:
(
UITableView
*
)
tableView
numberOfRowsInSection
:
(
NSInteger
)
section
{
//獲取組模型
JFFriendGroup
*friendGroup
=
self
.
friendGroups
[
section
]
;
//是否展開好友
if
(
friendGroup
.
isDisplay
)
{
return
friendGroup
.
friends
.
count
;
}
else
{
return
0
;
}
}
//創建Cell
-
(
UITableViewCell
*
)
tableView
:
(
UITableView
*
)
tableView
cellForRowAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
//獲取組模型
JFFriendGroup
*friendGroup
=
self
.
friendGroups
[
indexPath
.
section
]
;
//獲取單個好友模型
JFFriend
*myFriend
=
friendGroup
.
friends
[
indexPath
.
row
]
;
//創建cell
JFFriendCell
*cell
=
[
JFFriendCell
friendCellWithTableView
:tableView
]
;
//為Cell賦值
cell
.
myFriend
=
myFriend
;
return
cell
;
}
//創建headerView
-
(
UIView
*
)
tableView
:
(
UITableView
*
)
tableView
viewForHeaderInSection
:
(
NSInteger
)
section
{
JFFriendGroup
*friendGroup
=
self
.
friendGroups
[
section
]
;
JFHeaderView
*headerView
=
[
JFHeaderView
headerViewWithTableView
:tableView
]
;
//存儲組
headerView
.
tag
=
section
;
//指定控制器為代理
headerView
.
delegate
=
self
;
headerView
.
friendGroup
=
friendGroup
;
return
headerView
;
}
//點擊headerView按鈕的時候觸發
-
(
void
)
headerViewButtonDidClick
:
(
JFHeaderView
*
)
headerView
{
NSIndexSet
*indexSet
=
[
NSIndexSet
indexSetWithIndex
:headerView
.
tag
]
;
//刷新指定組
[
self
.
tableView
reloadSections
:indexSet
withRowAnimation
:UITableViewRowAnimationFade
]
;
}
|
關於重用:
UITableViewHeaderFooterView與UITableViewCell在滑動屏幕時都可以根據標志進行重用,而在不滑動而只進行reloadData等刷新數據操作時,兩者有不同表現:UITableViewHeaderFooterView將不能根據標志重用(即系統不會將其放入緩沖區),會創建新的視圖代替舊的。UITableViewCell能根據標志重用。所以在自定義UITableViewHeaderFooterView首尾視圖時,要注意刷新數據時對視圖的處理。