首页 > 代码库 > 21-30(NSTimer定时器 Cell的重用原理 代理的使用场合 UITableViewCell结构 监听键盘的通知)

21-30(NSTimer定时器 Cell的重用原理 代理的使用场合 UITableViewCell结构 监听键盘的通知)

21.NSTimer定时器

22.tableView的基本用法

23.tableView的常用属性

24.Cell的重用原理:

25.UITableViewCell结构

26.使用xib封装一个view的步骤

27.代理的使用场合

28.使用delegate的步骤

29.通过代码自定义cell步骤

30.监听键盘的通知

{

  细节决定成败, 这句话讲的太对了, 所以我们要注意每一个细节!今天还好注意了, 没犯错!嘿嘿!

  今天心情特别好, 心情好! 啥都好!

  给大家来个笑, 工作的同时,不要忘记笑容

 

      程序员的愿望:

  有一天一个程序员见到了上帝.

  上帝: 小伙子,我可以满足你一个愿望.

  程序员: 我希望中国国家队能再次打进世界杯.

  上帝: 这个啊!这个不好办啊,你还说下一个吧!

  程序员: 那好!我的下一个愿望是每天都能休息6个小时以上.

  上帝: 还是让中国国家打进世界杯.

  

  哈哈, 不加班你还是程序员嘛!

}


21.NSTimer定时器
定义一个定时器属性.
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];每隔2秒重复调用一次self 的nextImage方法
通过invalidate方法可以停止定时器的工作,一旦定时器被停止了,就不能再次执行任务。只能再创建一个新的定时器才能执行新的任务

//拿到当前的主线程消息,给分流一些时间让其去执行,定时器.这样就不会出现当其它的一些操作正在进行时, 定时器停止工作
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

 

22.tableView的基本用法

一般是控制器遵守UITableViewDataSource协议, 实现以下基本方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;// 一共有多少组数据
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; // 每一组有多少行数据
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;// 每一行显示什么内容
UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行
indexPath可以唯一的确定一个cell (indexPath.section//当前所在的列,indexPaht.row//当前所在的行);

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section//第section组显示的头部标题,属于数据源方法
{
  return @"头部标题";
}

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView//返回右边索引条显示的字符串数据,属于数据源方法
{
return [self.groups valueForKeyPath:@"title"];
}

有时候需要知道tableview发生的一些事情, 就要先设置它的代理,一般设控制器为其代理:遵守<UITableViewDelegate>协议
self.tableView.rowHeight = 60//设置行高(每一行的高度一致)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath//每一行的高度不一致的时候使用这个方法来设置行高 属于代理方法
{
  if (indexPath.row == 0) return 100;
  return 60;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath//当点击tableView的某一行时, 就会自动调用这个方法
{
  // 1.取得被点击这行对应的模型  
  Hero *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];//让窗口显示
  alert.tag = indexPath.row; // 绑定行号到alertView上目的是能够把是当前所在的行传到 UIAlertView代理方法中,供其使用.
}

一定要记得先修改模型再刷新表格

3.告诉tableView重新加载模型数据
reloadData : tableView会向数据源重新请求数据
重新调用数据源的相应方法取得数据
重新调用数据源的tableView:numberOfRowsInSection:获得行数
重新调用数据源的tableView:cellForRowAtIndexPath:得知每一行显示怎样的cell

 

// UIAlertView的代理方法,点击了alertView上面的按钮就会调用这个方法
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
  if (buttonIndex == 0) return;
  NSString *name = [alertView textFieldAtIndex:0].text;//取得文本框最后的文字
  // 2.修改模型数据
  int row = alertView.tag;
  Hero *hero = self.heros[row];
  hero.name = name;

  全部刷新

  [self.tableView reloadData];

  //局部刷新
  NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:0];//要刷新哪一行的
  [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationBottom];//刷新指定的行的数据
}

 

23.tableView的常用属性
self.tableView.separatorColor = [UIColor colorWithRed:255/255.0 green:255/255.0 blue:0 alpha:255/255.0];//设置每行分隔线的颜色
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;//设置分隔线的样式
self.tableView.tableHeaderView = [UIButton buttonWithType:UIButtonTypeContactAdd];//表格头部的控件

 

24.Cell的重用原理:
当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中 有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象
代码体现:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

  // 1.定义一个cell的标识
  static NSString *ID = @"cell"; 

  // 2.从缓存池中取出cell
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 

  // 3.如果缓存池中没有cell, 那么就自己创建一个带有标识 的cell
  if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
  }
  // 4.设置cell的属性以及数据...
  return cell;
}

 

25.UITableViewCell结构
UITableViewCell内部有个默认的子视图:contentView,

contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图。

可以通过设置UITableViewCell的 accessoryType来显示,默认是UITableViewCellAccessoryNone,为不显示状态

还可以通过cell的accessoryView属性来自定义辅助指示视图.

contentView下默认有3个子视图,其中2个是UILabel(通过UITableViewCell的textLabel和detailTextLabel属性访问)
第3个是UIImageView(通过UITableViewCell的imageView属性访问)
UITableViewCell还有一个UITableViewCellStyle属性,用于决定使用contentView的哪些子视图,以及这些子视图在contentView中的位置

 

26.使用xib封装一个view的步骤
1.新建一个xib文件描述一个view的内部结构(假设叫做MJTgCell.xib)
2.新建一个自定义的类(自定义类需要继承自系统自带的view, 继承自哪个类,  取决于xib根对象的Class)
3.新建类的类名最好跟xib的文件名保持一致(比如类名就叫做MJTgCell)
4.将xib中的控件 和 自定义类的.m文件 进行连线
5.提供一个类方法返回一个创建好的自定义view(屏蔽从xib加载的过程)
6.提供一个模型属性让外界传递模型数据
7.重写模型属性的setter方法,在这里将模型数据展示到对应的子控件上面

 

27.代理的使用场合
1.对象A内部发生了一些事情,想通知对象B
2.对象B想监听对象A内部发生了什么事情
3.对象A想在自己的方法内部调用对象B的某个方法,并且对象A不能对对象B有耦合依赖
4.对象A想传递数据给对象B
以上情况,结果都一样:对象B是对象A的代理(delegate)

28.使用delegate的步骤:
1.先搞清楚谁是谁的代理(delegate)
2.定义代理协议,协议名称的命名规范:控件类名 + Delegate
3.定义代理方法
代理方法一般都定义为@optional
代理方法名都以控件名开头
代理方法至少有1个参数,将控件本身传递出去
4.设置代理(delegate)对象 (比如myView.delegate = xxxx;)
5.代理对象遵守协议
6.代理对象实现协议里面该实现的方法
7.在恰当的时刻调用代理对象(delegate)的代理方法,通知代理发生了什么事情(在调用之前判断代理是否实现了该代理方法)

29.通过代码自定义cell步骤:
1.新建一个继承自UITableViewCell的类
2.重写initWithStyle:reuseIdentifier:方法
添加所有需要显示的子控件(不需要设置子控件的数据和frame,  子控件要添加到contentView中)
进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片)
3.提供2个模型
数据模型: 存放文字数据\图片数据
frame模型: 存放数据模型\所有子控件的frame\cell的高度
4.cell拥有一个frame模型(不要直接拥有数据模型)
5.重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame
6.frame模型数据的初始化已经采取懒加载的方式(每一个cell对应的frame模型数据只加载一次)

 

30.监听键盘的通知

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];

- (void)keyboardWillChangeFrame:(NSNotification *)note//当键盘改变了frame(位置和尺寸)的时候调用
{
  self.view.window.backgroundColor = self.tableView.backgroundColor;// 设置窗口的颜色
  CGFloat duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];//取出键盘动画的时间
  CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];//取得键盘最后的frame
  CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height;//计算控制器的view需要平移的距离
  [UIView animateWithDuration:duration animations:^{// 3.执行动画
  self.view.transform = CGAffineTransformMakeTranslation(0, transformY);让控制的View平移
  }];
}
注意:监听一个通知时, 必须在在dealloc中注销该通知,谨防对象销毁时,还向该对象发通知,造成野指针异常
- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}