UITableView
UITableView用来管理通用表格组件,通用表格组件需要考虑数据集的输入、每行数据的显示、行操作(包括点击、编辑、删除、插入、调整行顺序)。根据MVC编程的思想,UITableView只需要管理表格视图,和行操作,对数据的内部不需要干涉,由专门的数据来源提供。
TableVIew的数据来源是由UITableViewDataSource管理的,这是一个协议(protocal),只要遵守该协议的数据源都可以向UITableView提供数据。
每个table view是由多个区块(section)组成的。
上图中NSIndexPath指向的区域是一个section,每个section里都有section header和section footer。在中间是由行(row)组成的。
当用户用手点击其中的某一行,将向UITableViewDelegate发送一个事件响应消息,UITableViewDelegate再做出对应的响应。
代码实现
在ViewController.h头文件中加入对UITableDataSource和UITableViewDelegate的协议支持。
@interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
UITableDataSource协议中有两个required方法:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section \\\设置整个表格有几个区块 -(NSInteger)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath \\\设置表格中区块有几行
可在ViewController.m文件中添加所需的UITableDataSource协议中方法。
UITableView的style有plain、grouped两种属性
.dataSource经常使用的的方法有:
numberOfSectionsInTableView:
tableView:numberOfRowsInSection:
tableView:cellForRowAtIndexPath:
tableView:viewForHeader/FooterInSection:
.delegate经常使用的方法有:
tableView:didSelectRowAtIndexPath:
UITableViewCell的使用
重复使用与Cell Identifier
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"MyCell"];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyCell"];
}
return cell;
系统为UITableViewCell提供了不同的风格,包括:Default, Value1,Value2 Subtitle
如果想定制自己风格的表格有多种方法
1、用StoryBoard prototype 提供cell:可以用view tag访问界面,也可以用子类里的outlet访问界面。
2、用xib提供cell:可以用registerNib方法注册xib,也可以用registerClass的方法注册xib。
上课演示代码的详解:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ( section == 0) { //设置第一个区块有3行,其他区块有10行
return 3;
}
else {
return 10;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView * header = [[UIView alloc] init]; //创建了一个header
header.backgroundColor = [UIColor redColor]; //设置header的背景色
return header;
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView * footer = [[UIView alloc] init]; //创建了一个footer
footer.backgroundColor = [UIColor blueColor]; //设置footer的背景色
return footer;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
tableView.rowHeight = 128; // change it and watch number of cells alive.
NSString * cellID = [NSString stringWithFormat:@"cell_sec_%ld", (long)indexPath.section ];
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID]; // there are more built-in styles
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = [NSString stringWithFormat:@"%ld", (long)indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:@"section %ld - row %ld", (long)indexPath.section, (long)indexPath.row];
if ( indexPath.section == 0 ) {
cell.imageView.image = [UIImage imageNamed:@"gear"];
} else {
cell.imageView.image = [UIImage imageNamed:@"guitar"];
}
return cell;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:@"showDetail" sender:indexPath];
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ( [segue.identifier isEqualToString:@"showDetail"] ) {
DetailedViewController * dvc = segue.destinationViewController;
dvc.indexPath = sender;
}
UITableViewController
可以用来管理UITableView,当UITableView嵌在UITableViewController里时可以使用static cell,支持下拉刷新界面。
下拉刷新界面代码:
self.refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl.attributedTitle = [[NSAttributeString alloc] initWithString:@"Scan"]; //这段代码需要放到viewDidappear里
[self.refreshControl addTarget:self action:@selector(refreshing:)forControlEvents:UIControlEventValueChanged];
响应代码
- (IBAction)startRefresh:(id)sender{
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
当刷新表格时UITableView并不知道dataSource有变化,有一系列reload方法来让UITableView来更新变化。
reloadData 用来刷新整个表格
reloadRowsAtIndexPaths:withRowAnimation: 用来刷新行
reloadSections:withRowAnimation: 用来刷新整个区块
reloadSectionIndexTitles 用来刷新索引
刷新页面的关键代码
- (IBAction)startRefresh:(id)sender{
self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:@"scanning"];
[self performSelector:@selector(stopRefreshing) withObject:nil afterDelay:1.0]; //一秒钟以后停止刷新方法
}
- (void) stopRefreshing{
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
TableView的交互
在TableView中选择某一行是最基本的操作。
选中的响应
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath //选中某一行
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath //将某一行的状态改为未选中
-(void)selectRowAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition; //用代码选中,scrollPosition有几种选项可选,UITableScrollPositionTop, UITableScrollPositionMiddle,UITableScrollPositionBottom,UITableScrollPositionNone
-(void)deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;
NSIndexPath *indexPathForSelectedRow
NSArray<NSIndexPath *> *indexPathsForSelectedRows
控制表格滚动
- scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated
-scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated
上面代码中的UITableViewScrollPosition参数有四种
UITableScrollPositionTop 行出现在表顶
UITableScrollPositionMiddle 行出现在表中间
UITableScrollPositionBottom 行出现在表底
UITableScrollPositionNone 就近
编辑模式
编辑模式的响应过程
带索引的表格
高亮与菜单
表格的搜索:在iOS8以后,表格的搜索可以用UISearchController。
CollectionView
有的界面用TableView实现起来不怎么方便(比如横向滚动、一行放多个项目),我们可以使用CollectionView。
CollectionView是对UITableView的扩展,增加了网格式界面,对表格内部职责进一步细分,分离出了Layout类。
CollectionView总体结构与TableView相近,但有一些变化,在TableViewcell中的cell在CollectionView中叫item。header/footer在CollectionView中统一叫supplementary view。item view必须register。布局交给独立的layout类edit方法不再指定动画类型。
关键代码
创建 Collection View
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 13;
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ImageCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ImageCell" forIndexPath:indexPath];
cell.imageView.image = [self imageOfCityWithId:indexPath.item];
return cell;
}
提供 DataSource
-(UIImage*)imageOfCityWithId:(NSInteger)cityId {
return [UIImage imageNamed:[NSString stringWithFormat:@"city%d",(int)cityId]];
}
提供supplementary view的方式
-(UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
return [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"citiesHeader" forIndexPath:indexPath];
}
刷新数据
reloadData
reloadSections:(NSIndexSet *)
reloadItemsAtIndexPaths:(NSArray<NSIndexPath >)
将一组编辑或刷新动作合作到一个动画过程里
-performBatchUpdates:completion:
手工移动格子
beginInteractiveMovementForItemAtIndexPath: //开始拖动制定的格子
updateInteractiveMovementTargetPosition: //更新选定格子被拖到的位置
endInteractiveMovement 或 cancelInteractiveMovement //结束
CollectionView Delegate 里交互的相关方法