iOS基础——通过案例学知识之UITableView


案例一:英雄联盟展示

对于UITableView的知识点特别多,因为它是iOS用得最多控件之一,我会尽我最大努力和语言的组织,将所有知识点介绍到位,下面是要实现的效果图

吐槽

  • 与Android对比,可以说跟ListView的实现几乎一样,跟RecyclerView一模一样
  • Android写起来似乎比iOS复杂一点,因为iOS大部分都被封装好了,这一点iOS做得好
  • 对于iOS的方法的命名只能说又长又臭

知识点包括

  • UITableView的UITableViewDataSource
  • UITableView的UITableViewDelegate
  • UITableView的cell的重用

一、准备工作

1、准备数据源(plist)

2、布局文件

二、Model读取数据

分析plist数据的格式,然后创建对应的对象模型,并提供相应的初始化方法,这是mvc中经典的一个步骤

  • 特别注意:@property中属性不可以使用weak属性,否则在UITableView复用机制中会被回收,导致画面显示不出来
@interface HeroModel : NSObject
@property(nonatomic,strong) NSString *icon;
@property(nonatomic,strong) NSString *intro;
@property(nonatomic,strong) NSString *name;-(instancetype)initWithDict:(NSDictionary *)dict;
+(instancetype)HeroModelWithDict:(NSDictionary *)dict;
@end

在m文件中实现初始化方法,方法中实现字典转换为对象

@implementation HeroModel-(instancetype)initWithDict:(NSDictionary *)dict{if(self = [super init]){[self setValuesForKeysWithDictionary:dict];}return self;
}+(instancetype)HeroModelWithDict:(NSDictionary *)dict{return [[self alloc]initWithDict:dict];
}
@end

三、UITableView

1、声明委托代理,声明属性

要想UITableView有数据,那么就必须通过它的委托代理方法才能显示UITableView中的数据

@interface ViewController ()<UITableViewDataSource>
//存放数据的可变数组
@property (strong, nonatomic) NSMutableArray *dataArray;
//tableview
@property (strong, nonatomic) IBOutlet UITableView *tableView;
@end

2、实现属性的转换

毫无疑问是通过懒加载将plist的内容转为模型存进我们声明的可变数组中

#pragma 复写get方法
#pragma 懒加载,读取plist文件并转换为模型
- (NSMutableArray *)dataArray{if(nil == _dataArray){//初始化数组_dataArray = [NSMutableArray array];//获取plist文件路径NSString *path = [[NSBundle mainBundle]pathForResource:@"heros.plist" ofType:nil];//读取plist文件内容NSArray *tempArray = [NSArray arrayWithContentsOfFile:path];//遍历plist文件内容,存到可变数组中for (NSDictionary * dict in tempArray) {HeroModel *heroModel = [HeroModel HeroModelWithDict:dict];[_dataArray addObject:heroModel];}}//返回return _dataArray;
}

3、交付委托

//交付委托
_tableView.dataSource = self;

4、实现代理的方法

通过实现UITableViewDataSource代理的方法,来显示数据,类似于ListView的Adapter

#pragma UITableViewDataSource委托方法
#pragma 返回一共有多少组
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{//默认返回1组return 1;
}#pragma UITableViewDataSource委托方法
#pragma 返回一个组由多少行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{//返回数据的数量return self.dataArray.count;
}#pragma UITableViewDataSource委托方法
#pragma 返回每一行Item的内容
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{//创建tableview的itemUITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];//通过indexPath的行属性,取出对应的模型HeroModel *heroModel = _dataArray[indexPath.row];//设置文本信息cell.textLabel.text = heroModel.name;//设置图片信息UIImage *image = [UIImage imageNamed:heroModel.icon];cell.imageView.image = image;//设置详细信息文本cell.detailTextLabel.text = heroModel.intro;//设置最右边的箭头cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;//返回return cell;
}

① UITableView的显示有两种方式,在storyboard中可以设置

1.plain:数据平铺显示,中间没有空隙,数组的头标题有悬浮效果

2.group:数据分组显示,中间留有空隙

② UITableViewDataSource的委托方法,程序会按以下顺序执行

  1. numberOfSectionsInTableView:数据中有呈多少组展示(可选实现,默认返回1组)
  2. numberOfRowsInSection:数据中每组有多少行(必须实现,否则会报错)
  3. cellForRowAtIndexPath:数据中每行的内容(必须实现,否则会报错)

③ UITableViewCell的四种样式

1.UITableViewCellStyleDefault

2.UITableViewCellStyleValue1

3.UITableViewCellStyleValue2

4.UITableViewCellStyleSubtitle

④ cell.accessoryType的五种样式,用得不多就不解释了

  1. UITableViewCellAccessoryNone
  2. UITableViewCellAccessoryDisclosureIndicator
  3. UITableViewCellAccessoryDetailDisclosureButton
  4. UITableViewCellAccessoryCheckmark
  5. UITableViewCellAccessoryDetailButton

5、UITableViewDataSource其他代理方法

这两个代理方法会在group样式上展示得比较清晰

#pragma UITableViewDataSource委托方法
#pragma 返回tableview中头部的标题
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{return @"header";
}#pragma UITableViewDataSource委托方法
#pragma 返回tableview中底部的标题
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{return @"footer";
}

6、cell的重用

  • cell与ListView的Item中是一样的,它也是要对Item进行重用的
  • 这里的重用主要是用到重用标识符
  • 在cellForRowAtIndexPath方法中改一下cell的创建代码即可
//重用标识符,需要用static修饰,避免多次分配内存给NSString
static NSString *identifier = @"h1";
//从缓存池中取出tableview的item
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
//创建cell
if(nil == cell){cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}

7、tableView的属性介绍

  1. _tableView.separatorColor:分割线颜色
  2. _tableView.separatorInset:分割线缩进
  3. _tableView.separatorStyle:分割线类型
  4. _tableView.allowsMultipleSelection:允许选项多选
  5. _tableView.tableHeaderView:可以添加一个在头部的View
  6. _tableView.tableFooterView:可以添加一个在底部的View
  7. _tableView.sectionHeaderHeight:每个组的间隔

8、实现cell的点击事件

① 声明委托与交付委托

cell的点击事件是在UITableViewDelegate的实现方法

//声明委托
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
//交付委托
_tableView.delegate = self;

② 实现点击事件函数

#pragma UITableViewDelegate委托方法
#pragma 反选数据时调用
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{}#pragma UITableViewDelegate委托方法
#pragma 选择数据时调用
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{}

9、实现cell的编辑模式和cell的增加插入

cell的编辑模式和cell的增加插入也是在UITableViewDelegate的实现方法

#pragma UITableViewDelegate委托方法
#pragma 决定哪一行可进入编辑模式
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{if(indexPath.row == 2){return NO;}else{return YES;}
}#pragma UITableViewDelegate委托方法
#pragma 点击delete和insert的回调函数,该函数同时回开启侧滑删除功能
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{if(editingStyle == UITableViewCellEditingStyleDelete){//删除数组中的数据[_dataArray removeObjectAtIndex:indexPath.row];//tableview完成删除操作,更新UI[_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];}else if(editingStyle == UITableViewCellEditingStyleInsert){//模拟添加数据HeroModel *hero = [[HeroModel alloc]init];hero.name = @"寒冰射手";//添加到数组中[_dataArray insertObject:hero atIndex:indexPath.row];//tableview完成添加操作,更新UI[_tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];}
}#pragma UITableViewDelegate委托方法
#pragma 决定哪一行开启的编辑模式是插入模式还是删除模式
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{if(indexPath.row <= 5){return UITableViewCellEditingStyleInsert;}else{return UITableViewCellEditingStyleDelete;}
}#pragma UITableViewDelegate委托方法
#pragma 删除模式下的删除按钮文字显示
-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{return @"蹦瞎卡拉卡";
}

① UITableViewDelegate的委托方法

  1. canEditRowAtIndexPath:允许哪一行开启编辑模式
  2. commitEditingStyle:点击事件的回调,同时开启侧滑删除
  3. editingStyleForRowAtIndexPath:决定哪一行的编辑模式

② indexPath属性

  1. indexPath.row:行的索引
  2. indexPath.section:组的索引

③ 编辑模式动画,大家看名字应该都可以猜得出

  1. UITableViewRowAnimationFade
  2. UITableViewRowAnimationRight
  3. UITableViewRowAnimationLeft
  4. UITableViewRowAnimationTop
  5. UITableViewRowAnimationBottom
  6. UITableViewRowAnimationNone
  7. UITableViewRowAnimationMiddle
  8. UITableViewRowAnimationAutomatic

④ 最后只要开启编辑模式

_tableView.editing = YES;

源码下载


案例二:汽车展示

这是对上面博客缺少的内容进行补充,实现的效果如图

知识点

  • UITableViewController
  • 侧边字母导航栏

一、准备工作

1、准备数据源(plist)

2、布局文件

这次采用UITableViewController作为启动界面,其好处是自动将UITableViewDelegate和UITableViewDataSource自动绑定到对应的m文件中

不过需要注意的是m文件中必须实现UITableViewController

@interface ViewController : UITableViewController
@end

二、Model读取数据

跟上篇文章一样,分析Model中拥有的属性,这里包括有两个Model,Cars和Car,分别代表多辆车的集合和单辆车的数据

Cars的h文件

@interface Cars : NSObject
@property (nonatomic,strong)NSString *title;
@property (nonatomic,strong)NSArray *cars;-(instancetype)initWithDict:(NSDictionary *)dict;
+(instancetype)CarsModelWithDict:(NSDictionary *)dict;
@end

Cars的m文件

和Car有点区别,就是在初始化的时候,将Car的NSArray和转换成模型

@implementation Cars
-(instancetype)initWithDict:(NSDictionary *)dict{if(self = [super init]){[self setValuesForKeysWithDictionary:dict];//转换CarNSMutableArray *muta = [NSMutableArray array];for (NSDictionary *dict in self.cars) {Car *car = [Car CarModelWithDict:dict];[muta addObject:car];}self.cars = muta;}return self;
}
+(instancetype)CarsModelWithDict:(NSDictionary *)dict{return [[self alloc]initWithDict:dict];
}
@end

Car的h文件

@interface Car : NSObject
@property (nonatomic,strong)NSString *icon;
@property (nonatomic,strong)NSString *name;-(instancetype)initWithDict:(NSDictionary *)dict;
+(instancetype)CarModelWithDict:(NSDictionary *)dict;
@end

Car的m文件

@implementation Car
-(instancetype)initWithDict:(NSDictionary *)dict{if(self = [super init]){[self setValuesForKeysWithDictionary:dict];}return self;
}
+(instancetype)CarModelWithDict:(NSDictionary *)dict{return [[self alloc]initWithDict:dict];
}
@end

三、UITableView

1、属性声明

@interface ViewController ()
//存放数据数组
@property (nonatomic,strong)NSMutableArray *dataArray;
//存放索引数组
@property (nonatomic,strong)NSArray *indexArray;
@end

2、plist数据的加载

#pragma 复写set方法
#pragma 懒加载,读取plist文件内容
-(NSArray *)dataArray{if(nil == _dataArray){//初始化数组_dataArray = [NSMutableArray array];//获取plist文件路径NSString *path = [[NSBundle mainBundle]pathForResource:@"cars_total.plist" ofType:nil];//读取plist文件内容NSArray *tempArray = [NSArray arrayWithContentsOfFile:path];//遍历plist内容存放到可变数组for (NSDictionary  *dict in tempArray) {Cars *cars = [Cars CarsModelWithDict:dict];[_dataArray addObject:cars];}//取出索引_indexArray = [_dataArray valueForKey:@"title"];}return _dataArray;
}

3、由于UITableView是继承UITableViewController,所以可以直接使用其代理方法

#pragma UITableViewDataSource委托方法
#pragma 返回一共有多少组
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{return self.dataArray.count;
}#pragma UITableViewDataSource委托方法
#pragma 返回一组多少行
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{Cars *cars = self.dataArray[section];return cars.cars.count;
}#pragma UITableViewDataSource委托方法
#pragma 返回每一行Item的内容
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{//cell的重用static NSString *identifier = @"car";UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];if(nil == cell){cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];}//设置内容Cars *cars = self.dataArray[indexPath.section];Car *car = cars.cars[indexPath.row];UIImage *image = [UIImage imageNamed:car.icon];cell.textLabel.text = car.name;cell.imageView.image = image;return cell;
}#pragma UITableViewDataSource委托方法
#pragma 返回每一组的头部标题
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{return _indexArray[section];
}#pragma UITableViewDataSource委托方法
#pragma 返回右侧索引值
-(NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView{return _indexArray;
}

源码下载


案例三:设置列表

这个案例很简单,不用代码,直接使用storyboard就可以了,一般使用在固定的列表中使用

知识点

  • 静态Cell

一、准备数据

1、使用UITableViewController,设置内容为静态Cell,而且设置有三节内容

2、设置其style为分组

3、你会看到左手边会出现三节TableView

4、选中section可以设置TableViewCell的数量,设置头部标题

5、选中TableViewCell,设置其style,照片,文字,accessory

6、大功告成


案例四:应用管理

这个案例使用自定义Cell来完成,可以说是大多数UITableView的首选

知识点

  • 自定义Cell

一、准备数据

这里直接使用UITableView和UITableViewCell直接自定义我们的Cell

创建类继承自UITableViewCell

@interface TableViewCell : UITableViewCell
@end

记得填写UITableViewCell的类和Cell重用标识符

二、Model读取数据

根据plist文件有的属性创建我们的h文件

#import <Foundation/Foundation.h>@interface AppModel : NSObject
@property (nonatomic,strong)NSString * size;
@property (nonatomic,strong)NSString * download;
@property (nonatomic,strong)NSString * name;
@property (nonatomic,strong)NSString * icon;
//是否点击了下载按钮
@property(nonatomic,assign,getter=isDownloaded)BOOL *downloaded;-(instancetype)initWithDict:(NSDictionary *)dict;
+(instancetype)AppModelWithDict:(NSDictionary *)dict;
@end

m文件,固定的写法

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

三、UITableView

1、Cell的处理

在Cell的类文件中提供一个数据Model,并通过Model绑定我们的View的值

//h文件
#import <UIKit/UIKit.h>
#import "AppModel.h"@interface TableViewCell : UITableViewCell
@property (strong ,nonatomic)AppModel *appModel;
@end//m文件
#import "TableViewCell.h"@interface TableViewCell()
@property (weak, nonatomic) IBOutlet UIImageView *icon;
@property (weak, nonatomic) IBOutlet UILabel *name;
@property (weak, nonatomic) IBOutlet UILabel *download;
@property (weak, nonatomic) IBOutlet UIButton *down;@end@implementation TableViewCell-(void)setAppModel:(AppModel *)appModel{_appModel = appModel;_icon.image = [UIImage imageNamed:_appModel.icon];_name.text = appModel.name;_download.text = [NSString stringWithFormat:@"大小:%@ | 下载量:%@",appModel.size,appModel.download];_down.enabled = !appModel.isDownloaded;
}- (IBAction)actionDown:(id)sender {_down.enabled = NO;_appModel.downloaded = YES;
}@end

2、UITableView的处理

创建数组属性,读取plist文件内容,重写set方法

@interface ViewController ()
@property (nonatomic,strong)NSMutableArray *dataArray;
@end@implementation ViewController-(NSMutableArray *)dataArray{if(nil == _dataArray){_dataArray = [NSMutableArray array];NSString *path = [[NSBundle mainBundle]pathForResource:@"apps_full.plist" ofType:nil];NSArray *tempArray = [NSArray arrayWithContentsOfFile:path];for (NSDictionary *dict in tempArray) {AppModel *appmodel = [AppModel AppModelWithDict:dict];[_dataArray addObject:appmodel];}}return _dataArray;
}

UITableViewDataSource委托的实现方法

- (void)viewDidLoad {[super viewDidLoad];
}-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{return self.dataArray.count;
}-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{static NSString *identifier = @"appCell";TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];cell.appModel = self.dataArray[indexPath.row];return cell;
}
@end

这样就好了,其实很简单

源码下载

结语

学习UITableView应该掌握以下的知识点

  • 字典转模型
  • 双模型转换
  • 决定组数
  • 决定行数
  • 决定每行内容
  • Header标题
  • Header自定义View
  • Footer标题
  • Footer自定义View
  • 插入/删除操作
  • 点击/非点击操作
  • Cell重用
  • 自定义Cell

iOS基础——通过案例学知识之UITableView相关推荐

  1. IOS基础知识-ARC,分类,Block

    IOS基础知识-ARC,分类,Block ARC快速入门 本小节知识点: 1.ARC机制判断 2.ARC快速使用 ARC基本概念 本小节知识点: 1.什么是ARC 2.ARC的注意点和优点 3.ARC ...

  2. ios基础考试题1,实现按钮点击改变位置和图片的透明度和动画的使用

    ios基础考试题1,实现按钮点击改变位置和图片的透明度和动画的使用 考察frame,center,bounds的坐标,改变,动画的使用,图片容器的UIImageView的透明度等知识 oc写法 // ...

  3. IOS基础之仿酷狗音乐第1天

    IOS基础之仿酷狗音乐第1天 细节较多,涉及字典转模型,tableView 的使用,模态框,自定义模态,音视频播放,全局PCH文件,xib加载,自定义 xib ,info.plist文件的加载,动画的 ...

  4. iOS开发UI篇-在UItableview中实现加载更多功能

    iOS开发UI篇-在UItableview中实现加载更多功能 一.实现效果 点击加载更多按钮,出现一个加载图示,三秒钟后添加两条新的数据. 二.实现代码和说明 当在页面(视图部分)点击加载更多按钮的时 ...

  5. 作为第一期iOS基础班学生,MJ广东开校之我见(原稿)

    作为第一期iOS基础班学生,MJ广东开校之我见 先作自我介绍,我是2015年4月6日开班的第一期iOS基础班成员.我的名字叫静静(一看就是骗人的哈哈.).不得不说,来到黑马真的是我从老家出来6年里面最 ...

  6. iOS基础问答面试题连载-附答案

    2017-02-02 timhbw CocoaChina 以下是一些自己收集的比较基础的问题(大神可以忽略),附上答案,方便大家阅读.俗话说得好,基础不牢,地动山摇.文章末尾会提供PDF版的文档,方便 ...

  7. J2EE学习笔记三:EJB基础概念和知识 收藏

    J2EE学习笔记三:EJB基础概念和知识 收藏 EJB正是J2EE的旗舰技术,因此俺直接跳到这一章来了,前面的几章都是讲Servlet和JSP以及JDBC的,俺都懂一些.那么EJB和通常我们所说的Ja ...

  8. 第一台计算机豹电器元件,电气基础和安全知识.ppt

    电气基础和安全知识 电工基础 第一章 基础知识 第二章 电工安全基本知识 第三章 常用仪表与测量 第四章 常用控制电器 第1章 基础知识 1.1 电工基础知识 1.2 电力的产生 1.1 电工基础知识 ...

  9. IOS基础之iPad的屏幕旋转方向判断

    IOS基础之iPad的屏幕旋转方向判断 #pragma mark - 屏幕旋转 - (void)viewWillTransitionToSize:(CGSize)size withTransition ...

最新文章

  1. 个人银行账户管理程序
  2. 启用WebApi 2里的Api描述信息(Help下的Description)
  3. 最新全球自由职业技能单日排行
  4. 从构建分布式秒杀系统聊聊线程池
  5. python列表中的冒号_python 列表中[ ]中冒号‘:’的作用
  6. [Machine Learning]--无监督学习
  7. 行为设计模式 - Memento设计模式
  8. memcached全面剖析–2. 理解memcached的内存存储
  9. Cocoapods的安装及使用
  10. vux2.9版本bug
  11. 深度可分离卷积组卷积
  12. 计算机网络中属于通信子网,计算机网络通常被划分为通信子网和资源子网,通信子网提供信息传输服务,资源子网提供共享资源。...
  13. hdu 3987 求割边最少的最小割
  14. 一个电脑白痴和一个黑客的超爆笑的对话
  15. python 字节流分段_如何在Python中编写简单代码,并且速度超越Spark?
  16. 用画中画剪辑技巧,给每个视频添加背景图片
  17. python ai教程_带有Python的AI教程
  18. windows分屏和半屏
  19. 阿里云建站,重启阿里云服务器后网站打不开,该怎么办???如何检查TCP 80端口是否正常工作???
  20. 1.2 计算机的分类和应用

热门文章

  1. 2017年暑期全国高校教师 “Python编程及应用”培训班通知
  2. python里延时回调普通函数
  3. java参考中文站 http://www.javaref.cn
  4. 防火墙控制Docker端口开放与关闭
  5. python递归算法(斐波那契数列,汉诺塔、二分法查找)
  6. 修改screen会话名称
  7. C++程序设计实践里面石头剪刀布版王者农药实例
  8. 基于pynput的微信刷屏代码
  9. 你是什么命,好玩的很
  10. 修改mysql默认管理员账户名称