Contents
  1. UITableView
    1. TableView 的一些知识总结
    2. TableViewCell注意点
    3. TableViewController注意点
    4. UITableView的referance
      1. 这里是展示cell的时候的回调
      2. 设定高度
      3. Section的头尾
      4. Selection选择事件
      5. 编辑状态
      6. 定义长按cell的copy和paste
      7. 设定cell的焦点
      8. Data刷新 (刷新可见行,visibleCell,基于cell重用机制)
      9. 行所对应的视图关系和坐标
      10. 滚动列表到某一行或者临近行
      11. 行的插入、删除、刷新
      12. 参考博文

UITableView

TableView 的一些知识总结

TableViewCell注意点

  1. 每个TableViewCell里带一个contentView,cell的textLabel和imageView都是加载在contentView里的,所以以后要在cell上添加控件最好在contentView上添加,以免不必要的错误。

    contentView.png

  2. 创建自定义TableViewCell

    首先调用cellForRowAtIndexPath方法,如果是加载nib可以在ViewDidLoad中先注册nib文件的cell:

1
2
UINib * nib = [UINib nibWithNibName:NSStringFromClass([MZTableViewCell class]) bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:@"mzCellNib"];
然后从缓存池里查找
1
2
static NSString *reuseID = @"mzCellNib";
MZTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseID];
如果storyboard中有cell的话,设置storyboard中cell的重用标识,在缓存池中也能找到:

![storyboard设置cell.png](http://oc98nass3.bkt.clouddn.com/storyboard设置cell.png)

如果缓存池没有,storyboard里面也木有这样标识的cell的话就有两种方式来创建:

  • 1.创建一个继承自UITableViewCell的子类,比MZTableViewCell
1
2
3
if (cell == nil) {
cell = [[MZTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseID];
}
  • 2.也可以自己创建cel:从Nib里加载cell
1
2
3
4
if (cell == nil) {
//加载xib文件加载cell,方法放回的是一个数组,取最后一个对象
cell = [[[NSBundle mainBundle loadNibNamed:NSStringFromClass([MZTableViewCell class]) owner:nil options:nil] lastObject];
}

注意 如果nib,storyboard和.m文件中同时存在自定义的cell的话,需要注意cell的重用标识和代码的执行顺序,这里贴一张view的生命周期:

viewLifeCycle.png

TableViewController注意点

  1. TableViewController中自带了一个tableView,继承了代理和数据源协议。其中的self.view和self.tableView都指的是所自带的tableView。
  2. TableViewController还有一个UIRefreshControl,可以用来实现下拉刷新的效果。

UIRefreshControl使用非常简单,但是必须是在UITableViewController子类使用,而不能在UIViewController子类中使用。例如CustomViewController继承自UIViewController,那么就不能使用UIRefreshControl。

UIRefreshControl使用很简单,如下代码,RootTableViewController继承自UITableViewController,

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
//RootTaleiewController.h file
@interface RootTableViewController:UITableViewController
{
}
@end
//RootTableViewController.m file
@interface RootTableViewController()
@end
@implementation RootTableViewController
//省略不相干代码
- (void)viewDidLoad
{
[super viewDidLoad];
//初始化UIRefreshControl
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];
[self setRefreshControl:refreshControl];
}
/*
解释一下下面的代码:
当用户向下下拉刷新的时候,refresh触发,这时候请求url链接中的内容。这里使用AFNetworking来解析,代码块中的内容就是解析成功之后,设置数据源self.tweets中的内容,然后刷新UITableView界面,然后向UIRefreshControl对象发送endRefreshing消息,停止UIRefreshControl的动画效果。如果失败的话,也要停止UIRefreshControl的动画效果。
*/
- (void)refresh:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://search.twitter.com/search.json?q=ios%20development&rpp=100&include_entities=true&result_type=mixed/"];
// Initialize URL Request
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url];
// JSON Request Operation
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:urlRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSArray *results = [(NSDictionary *)JSON objectForKey:@"results"];
if ([results count]) {
self.tweets = results;
// Reload Table View
[self.tableView reloadData];
// End Refreshing
[(UIRefreshControl *)sender endRefreshing];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// End Refreshing
[(UIRefreshControl *)sender endRefreshing];
}];
// Start Operation
[operation start];
}
@end

另外在iOS6和iOS7上面,效果是不同的,在iOS6效果如下图:

iOS6_RefreshControl

在iOS7运行效果如下图所示:

iOS7_RefreshControl

UITableView的referance

1
@protocol UITableViewDelegate<NSObject, UIScrollViewDelegate>
这里是展示cell的时候的回调
1
2
3
4
5
6
7
8
9
10
@optional
// Display customization 这里是展示cell的时候的回调
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
设定高度

(注意estimatedHeightForRowAtIndexPath方法)

1
2
3
4
5
6
7
8
9
10
// Variable height support
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
// Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table.
// If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be displayed, so more expensive logic can be placed there.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
Section的头尾
1
2
3
4
// Section header & footer information. Views are preferred over title should you decide to provide both
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; // custom view for header. will be adjusted to default or specified header height
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; // custom view for footer. will be adjusted to default or specified footer height
Selection选择事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Selection
// -tableView:shouldHighlightRowAtIndexPath: is called when a touch comes down on a row.
// Returning NO to that message halts the selection process and does not cause the currently selected row to lose its selected look while the touch is down.
- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
// Called before the user changes the selection. Return a new indexPath, or nil, to change the proposed selection.
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
// Called after the user changes the selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
编辑状态
1
2
3
4
5
6
7
8
9
10
11
12
13
// Editing
// Allows customization of the editingStyle for a particular cell located at 'indexPath'. If not implemented, all editable cells will have UITableViewCellEditingStyleDelete set for them when the table has editing property set to YES.
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
- (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED; // supercedes -tableView:titleForDeleteConfirmationButtonForRowAtIndexPath: if return value is non-nil
// Controls whether the background is indented while editing. If not implemented, the default is YES. This is unrelated to the indentation level below. This method only applies to grouped style table views.
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
// The willBegin/didEnd methods are called whenever the 'editing' property is automatically changed by the table (allowing insert/delete/move). This is done by a swipe activating a single row
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath __TVOS_PROHIBITED;
- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath __TVOS_PROHIBITED;

Calling sequence for reordering a row in a table view.png
  上图中当tableView进入到edit模式的时候,tableView会去对当前可见的cell逐个调用dataSource的tableView:canMoveRowAtIndexPath:方法(此处官方给出的流程图有点儿问题),决定当前cell是否显示reoedering控件,当开始进入拖动cell进行拖动的时候,每滑动过一个cell的时候,会去掉用delegate的tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:方法,去判断当前划过的cell位置是否可以被替换,如果不行则给出建议的位置。当用户放手时本次reordering操作结束,调用dataSource中的tableView:moveRowAtIndexPath:toIndexPath:方法更新tableView对应的数据。

 当tableView进入编辑模式以后,cell上面显示的delete还是insert除了跟cell的editStyle有关,还与 tableView的delegate的tableView:editingStyleForRowAtIndexPath:方法的返回值有关(在这里唠叨一句,其实delegate提供了很多改变cell属性的机会,如非必要,还是不要去实现这些方法,因为执行这些方法也造成一定的开销)。

  delete和insert的流程如下苹果官方文档中给出的图所示:
Calling_sequence_for_inserting_or_deleting_rows_in_a_table_view.png

定义长按cell的copy和paste
1
2
3
4
5
// Copy/Paste. All three methods must be implemented by the delegate.
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(5_0);
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender NS_AVAILABLE_IOS(5_0);
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender NS_AVAILABLE_IOS(5_0);
设定cell的焦点

使用Apple TV遥控器控制屏幕上的用户界面 = =

1
2
3
4
5
// Focus
- (BOOL)tableView:(UITableView *)tableView canFocusRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
- (BOOL)tableView:(UITableView *)tableView shouldUpdateFocusInContext:(UITableViewFocusUpdateContext *)context NS_AVAILABLE_IOS(9_0);
- (void)tableView:(UITableView *)tableView didUpdateFocusInContext:(UITableViewFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator NS_AVAILABLE_IOS(9_0);
- (nullable NSIndexPath *)indexPathForPreferredFocusedViewInTableView:(UITableView *)tableView NS_AVAILABLE_IOS(9_0);
Data刷新 (刷新可见行,visibleCell,基于cell重用机制)
1
2
3
// Data
- (void)reloadData; // reloads everything from scratch. redisplays visible rows. because we only keep info about visible rows, this is cheap. will adjust offset if table shrinks
- (void)reloadSectionIndexTitles NS_AVAILABLE_IOS(3_0); // reloads the index bar.
行所对应的视图关系和坐标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@property (nonatomic, readonly) NSInteger numberOfSections;
- (NSInteger)numberOfRowsInSection:(NSInteger)section;
- (CGRect)rectForSection:(NSInteger)section; // includes header, footer and all rows
- (CGRect)rectForHeaderInSection:(NSInteger)section;
- (CGRect)rectForFooterInSection:(NSInteger)section;
- (CGRect)rectForRowAtIndexPath:(NSIndexPath *)indexPath;
- (nullable NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point; // returns nil if point is outside of any row in the table
- (nullable NSIndexPath *)indexPathForCell:(UITableViewCell *)cell; // returns nil if cell is not visible
- (nullable NSArray<NSIndexPath *> *)indexPathsForRowsInRect:(CGRect)rect; // returns nil if rect not valid
- (nullable __kindof UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath; // returns nil if cell is not visible or index path is out of range
@property (nonatomic, readonly) NSArray<__kindof UITableViewCell *> *visibleCells;
@property (nonatomic, readonly, nullable) NSArray<NSIndexPath *> *indexPathsForVisibleRows;
- (nullable UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (nullable UITableViewHeaderFooterView *)footerViewForSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
滚动列表到某一行或者临近行
1
2
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;
- (void)scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;
行的插入、删除、刷新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Row insertion/deletion/reloading.
- (void)beginUpdates; // allow multiple insert/delete of rows and sections to be animated simultaneously. Nestable
- (void)endUpdates; // only call insert/delete/reload calls or change the editing state inside an update block. otherwise things like row count, etc. may be invalid.
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);
- (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);


参考博文

UITableView学习笔记

Contents
  1. UITableView
    1. TableView 的一些知识总结
    2. TableViewCell注意点
    3. TableViewController注意点
    4. UITableView的referance
      1. 这里是展示cell的时候的回调
      2. 设定高度
      3. Section的头尾
      4. Selection选择事件
      5. 编辑状态
      6. 定义长按cell的copy和paste
      7. 设定cell的焦点
      8. Data刷新 (刷新可见行,visibleCell,基于cell重用机制)
      9. 行所对应的视图关系和坐标
      10. 滚动列表到某一行或者临近行
      11. 行的插入、删除、刷新
      12. 参考博文