3.cell常见属性
tableView展示数据的步骤:
1.tableView有一个数据源属性, 如果想充当tableView的数据源, 必须要遵守对应的协议, 任何对象都可以充当TableView的数据源, 只要其遵守协议, 实现相应的方法
协议里面有一些方法, 方法里面最基础的有一开始的三个方法
属性:
-
accessoryType
: 属性作用:
设置右边指示器的类型(每一个cell显示的)例如在设置中每一个cell
右边有一个箭头, 这个箭头就是指示器
-
UITableViewCellAcessoryDislosureIndicator
指示器为箭头 -
UITableViewCellAcessoryCheckmark
指示器为对勾 -
[站外图片上传中……(1)]
指示器为圆圈箭头 -
UITableViewCellAccessoryDetailButton
指示器为圆圈i
由于本人的语言不是很生动, 所以上面对指示器描述不是很准确,希望大家自己试试
-
accessoryView
: (如果系统给的指示器不够用, 我们可以利用这个增加自己需要的控件)
例如:cell.accessoryView = [[UISwich alloc] init];
这个就是一个开关 -
backgroundView
:设置背景
// 设置背景(背景view不用设置尺寸, backgroundView的优先级 > backgroundColor)
UIImageView *bgView = [[UIImageView alloc] init];
bgView.image = [UIImage imageNamed:@"buttondelete"];
cell.backgroundView = bgView;
-
selectedBackgroundView
选中时设置背景
UIView *selectedbgView = [[UIView alloc] init];
selectedbgView.backgroundColor = [UIColor greenColor];
cell.selectedBackgroundView = selectedbgView;
以上的两段代码就是如果设置,我们的背景图片, 当然,设置背景颜色, 也是类似的. 但是还是有些不同.
04-tableView的常见属性
1. separatorStyle
:分隔线样式
每一行都有线, 这个就是分隔线
2. separatorColor
:分隔线颜色
有时候, 我们的颜色种类可能不够
这个时候, 我们就要了解叫做RGB的东西
颜色有: 32位颜色, 24位颜色
R就是Red ; G就是Green ; B就是Blue
** 32位颜色分为**
- Alpha : 8位(这个是透明)
- Red : 8位
- Green : 8位
- Blue : 8位
** 24位颜色分为**
- Red : 8位
- Green : 8位
- Blue : 8位
然后, 我们在写程序中需要掌握的是:
我们的颜色是按照十六进制来存储的, 而且, 他们的存储方法是是这样的:
#ff ff ff ff // 这个代表的是白色(所有的颜色, 都是满格)透明度
前两个ff代表的是t, 后面的依次是R, G, B
-----------------------------------
#ff 00 00 00 // 这个代表的是黑色, 每一种颜色都是空
注意
- 这里面的黑色是最纯洁的
- 白色, 是最不纯洁的
- 每一个颜色通道占据8个二进制位
- 每一个颜色通道的取值范围是[0, 225]
#ff ff 00 00 // 这个代表的是红色
之所以讲这些, 是由于我们的这个有这么一个方法就是可以根据你自己的想法设计颜色
self.tableView.separatorColor = [UIColor colorWithRed: CGFloat green: CGFloat blue: CGFloat alpha: CGFloat];
要注意我在上面每一个参数的写法:
self.tableView.separatorColor = [UIColor colorWithRed: 78/225.0 green: 100/225.0 blue: 225/225.0 alpha: 225/225.0];
这个是苹果官方要求我们这样写, 这样表示的是每一份颜色所占总的比例
3. TableHeadView:
在我们的手机新浪微博中, 这个头部的控件是用来放置我们的广告的, 所以以后, 我们再使用的时候, 就不需要增加scollView了
** 调用方法:**
self.tableView.headView = ......
4. TablefootView:
用来加载更多时候用的, 我们在使用新浪微博, 或者在各大新闻软件中, 底部会有一个点击加载的地方
05. cell的循环利用
1. 分析
**1. ** 其实, 在我们的英雄展示那个程序的时候, 我们其中的一个方法- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
我们都知道, 我们一共有97个英雄, 但是这就意味着我们的这个方法会一次性调用97次吗???
答案是否定的, 其实, 我们的cell
的创建不是一次完成的, 我们可以在这个方法中试着打印 , 我们会发现, 他会打印7次, 或者8次.
这是由于,苹果官方在开发的时候, 为了性能的优化, 有这样的一个规律:
每当有cell
进入我们的视野的时候, 新进来的cell
就会被创建. 但是, 如果cell
离开我们的视野之后, 再进入视野, 这个cell
又会被重新创建
这样就会导致我们的性能的损耗
**2. ** 所以在这里我们就用到了, 新的知识:
-
cell
的循环利用
注意: 假设,我们的手机屏幕只可以放下7个cell
那么当我们将手机屏幕向下拖动的时候, 最多可以显示8个cell
,当我们继续拖动的时候, 我们会发现, 手机屏幕中的第一个cell
会离开我们的手机屏幕, 这个时候注意: 系统中TableView中会有一个缓存池, 而且这个缓存池系统会帮我们维护
, 专门存放我们的这个离开手机屏幕的cell
, 等到, 我们拖动到要显示第9个cell
的时候, 我们可以判断缓存池中是否有cell
, 如果有, 我们就直接拿过来, 并将以前的数据覆盖掉. - 离开屏幕就到缓存池, 出现新的
cell
就先到缓存池找是否有cell
如果有就直接覆盖数据, 拿过来用. 如果没有, 就创建一个新的cell
- 当然, 以后我们的需要使用
TableView
中更加复杂的东西的时候, 我们的缓存池可能存放的不止一种cell
这个时候, 我们就需要在提前对我们的每一个cell
加一个标识, 方便以后查找
2. 步骤:
所以根据上的说的, 我们想要实现cell
循环使用需要以下三步:
- 通过一个标识去缓存池中寻找可循环利用的
cell
- 如果缓存池中找不到可循环的
cell
; 创建一个新的cell
并给其贴一个标识 - 给
cell
设置新的数据
3. 代码重写:
// 离开屏幕的cell会怎样
/**
* 每当有一个cell进入视野范围内,就会调用
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// static修饰局部变量:可以保证局部变量只分配一次存储空间(只初始化一次)
static NSString *ID = @"hero";
// 1.通过一个标识去缓存池中寻找可循环利用的cell
// dequeue : 出列 (查找)
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 2.如果没有可循环利用的cell
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
// 3.给cell设置新的数据
// 取出模型
MJHero *hero = self.heros[indexPath.row];
// 设置cell的数据
cell.textLabel.text = hero.name;
cell.detailTextLabel.text = hero.intro;
cell.imageView.image = [UIImage imageNamed:hero.icon];
return cell;
}
6. 多组汽车品牌展示:
效果展示:
1. 注意点
- 今天的多组数据, 与以往不同.
先说plist文件的加载:
以往我们的plist文件的加载, 是只需要一个模型类. 今天做的这个程序是需要两个模型类, 一个用来存储: 汽车的数据
另一个使用来存储汽车组的数据
在我们的这个知识点中, 其实只有一个: 那就是关于字典转模型的更深一层的了解.
2. 知识点:
- 两个模型类:
上面我们介绍到了, 一个模型类用来存储汽车组数据的
, 因为我们的这次的plist文件要比以往复杂:
而且, 我们以前在数组转模型的时候, 一行代码便可, 现在不可以了
**以前的代码: **
@implementation MJCar
+ (instancetype)carWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end
**现在的代码: **
@implementation MJCarGroup
+ (instancetype)groupWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
// 赋值标题
self.title = dict[@"title"];
// 取出原来的字典数组
NSArray *dictArray = dict[@"cars"];
NSMutableArray *carArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
MJCar *car = [MJCar carWithDict:dict];
[carArray addObject:car];
}
self.cars = carArray;
}
return self;
}
@end
这是由于, 一开始的第一个模型转数组的时候 , 它只是将他的title
转成了模型, 而我们的car
虽然是个模型, 因为他里面还有数组并没有转成模型, 所以,我们需要创建两个模型类
- 关于右边的那个索引条
右边的那个索引条是我们的数据源自带的一个方法, 上面的字母是我们提前在plist文件中有的.
那个索引条上面的字母是我们随意写的, 而且, 他是按照从上到下的顺序, 帮助我们进行快速查找, 假如说, 我们将A
与B
的位置互相调换一下之后, 当我们点击B
的时候, 他会向我们展示的是A
类的汽车
3. 代码:
控制器.m文件
#import "MJViewController.h"
#import "MJCarGroup.h"
#import "MJCar.h"
@interface MJViewController ()<UITableViewDataSource>
/**
* 车品牌组数据
*/
@property (nonatomic, strong) NSArray *groups;
@end
@implementation MJViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (NSArray *)groups
{
if (_groups == nil) {
// 初始化
// 1.获得plist的全路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"cars_total.plist" ofType:nil];
// 2.加载数组
NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
// 3.将dictArray里面的所有字典转成模型对象,放到新的数组中
NSMutableArray *groupArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
// 3.1.创建模型对象
MJCarGroup *group = [MJCarGroup groupWithDict:dict];
// 3.2.添加模型对象到数组中
[groupArray addObject:group];
}
// 4.赋值
_groups = groupArray;
}
return _groups;
}
#pragma mark - 数据源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.groups.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
MJCarGroup *group = self.groups[section];
return group.cars.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.定义一个循环标识
static NSString *ID = @"car";
// 2.从缓存池中取出可循环利用cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 3.缓存池中没有可循环利用的cell
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
// 4.设置数据
MJCarGroup *group = self.groups[indexPath.section];
MJCar *car = group.cars[indexPath.row];
cell.imageView.image = [UIImage imageNamed:car.icon];
cell.textLabel.text = car.name;
return cell;
}
/**
* 第section组显示的头部标题
*/
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
MJCarGroup *group = self.groups[section];
return group.title;
}
/**
* 返回右边索引条显示的字符串数据
*/
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return [self.groups valueForKeyPath:@"title"];
}
// 这个是隐藏状态栏
- (BOOL)prefersStatusBarHidden
{
return YES;
}
@end
CarGroup. h
#import <Foundation/Foundation.h>
@interface MJCarGroup : NSObject
/**
* 这组的标题
*/
@property (nonatomic, copy) NSString *title;
/**
* 存放的所有的汽车品牌(里面装的都是MJCar模型)
*/
@property (nonatomic, strong) NSArray *cars;
+ (instancetype)groupWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
CarGroup. m
#import "MJCarGroup.h"
#import "MJCar.h"
@implementation MJCarGroup
+ (instancetype)groupWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
// 赋值标题
self.title = dict[@"title"];
// 取出原来的字典数组
NSArray *dictArray = dict[@"cars"];
NSMutableArray *carArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
MJCar *car = [MJCar carWithDict:dict];
[carArray addObject:car];
}
self.cars = carArray;
}
return self;
}
@end
Car.h
#import <Foundation/Foundation.h>
@interface MJCar : NSObject
/**
* 图标
*/
@property (nonatomic, copy) NSString *icon;
/**
* 名称
*/
@property (nonatomic, copy) NSString *name;
+ (instancetype)carWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
Car.m
#import "MJCar.h"
@implementation MJCar
+ (instancetype)carWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
@end
7. 数据刷新
**目的: **
上午我们讲了一些关于汽车品牌的, 但是, 我们注意到那上面的数据都是死的, 不能修改, 所以今天我们就做这个刷新的功能
我们今天利用上次的英雄展示那个应用 来完成今天的知识点. 效果就是:
当我们点击其中的一行的时候, 会弹出一个框, 然后里面课可以修改我们英雄的数据
1. 效果图:
2. 步骤:
在我们的storyboard界面将我们的tableView连线. 和我们的控制器链接 ,然后, 再遵守我们的协议, 使之成为我们tatableView的代理
由于我们在后面同样需要弹框(
AlerView
)这个效果, 而且要监听AlerView
内部 确认或者取消按钮的点击, 所以同样的我们需要遵守AlerView
的协议成为他的代理-
协议名称:
<UITableViewDataSource, UITableViewDelegate, UIAlertViewDelegate>
1. tableView的代理
- 取得我们被点击的模型
- 设置弹框
- 设置对话框的类型
- 取得唯一的那个文本框,显示英雄的名称
- 绑定行号到alertView上
绑定行号的作用是后面我们在修改数据模型的时候, 可以取得该行号, 当然, 这个其实是我们的
AlerView
的独有的渠道, 为了就是方便我们的方法之间传递参数
**代码: **
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1.取得被点击这行对应的模型
MJHero *hero = self.heros[indexPath.row];
// 弹框
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"数据展示" message:nil delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
// 设置对话框的类型
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
// 取得唯一的那个文本框,显示英雄的名称
[alert textFieldAtIndex:0].text = hero.name;
[alert show];
// 绑定行号到alertView上
alert.tag = indexPath.row;
}
2.
/**
* 点击了alertView上面的按钮就会调用这个方法
*
* @param buttonIndex 按钮的索引,从0开始
*/
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) return;
// 按钮的索引肯定不是0
// 1.取得文本框最后的文字
NSString *name = [alertView textFieldAtIndex:0].text;
// 2.修改模型数据
int row = alertView.tag;
MJHero *hero = self.heros[row];
hero.name = name;
// 3.告诉tableView重新加载模型数据
// reloadData : tableView会向数据源重新请求数据
// 重新调用数据源的相应方法取得数据
// 重新调用数据源的tableView:numberOfRowsInSection:获得行数
// 重新调用数据源的tableView:cellForRowAtIndexPath:得知每一行显示怎样的cell
// 全部刷新
// [self.tableView reloadData];
// 局部刷新
NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationBottom];
}
作者说:
这个是我现在学的所有的东西了, 现在我用的是Markdown
不用像以前一样, 还要把笔记整理一遍
这样做的好处就是更新的更加容易, 也快一点.
坏处就是可能我在做笔记的时候, 知识点比较散乱, 所以各位见谅哈!!!