第九天,静态单元格,和headfootview,原型cell以及一些重用bug的修复

1. 使用UITableView的"静态单元格"

(注意: 使用静态单元格, 必须使用UITableViewController控制器)

    * 什么是静态单元格? 什么是动态单元格?

    1> 静态单元格不会随着数据的改变而改变, 当在storyboard中设计的时候是什么样子, 最后运行效果就是什么样子, 并且不会随着数据的变化而变化。如果要想改变静态单元格内容, 必须重新修改代码。

    2> 动态单元格在设计的时候只是将单元格的"框架(壳子)"设计好了, 设置好了位置、大小、背景色等基本信息, 里面的具体数据内容, 需要在程序运行时, 通过动态获取数据再显示到单元格中。优点: 只要修改了数据模型, 那么对应的单元格内容就发生变化了。

 

 

    * 什么情况下使用静态单元格?什么情况下使用动态单元格?

    1> 静态单元格使用场景: 有些界面的内容是固定的, 并且基本上不会发生任何改变, 此时使用"静态单元格"来创建该界面, 非常方便。

    2> 动态单元格使用场景: 有些界面的内容会随着数据的变化而不断变化, 这些界面都需要使用"动态单元格", 随时根据相应的数据而变化。

 

 

    ** 演示:通过数据源方法来实现"QQ动态"界面效果。(使用UITableViewController)

    1> 分析如果要把动态内容的数据使用plist文件来保存, 那么如何设计该plist文件。

 

 

    ** 演示:通过使用"静态单元格"的方式来实现"QQ动态"界面效果。

    /********************************************************************************************/

    (注意: 使用静态单元格, 必须使用UITableViewController控制器)

    /********************************************************************************************/

 

 

    * 静态单元格使用建议:

    1> 先保留1个Section, 1个Cell。

    2> 设置好这个Cell以后, 在设置section的个数以及每个section中行的个数。

 

    * 静态单元格设置大致步骤:

    1> 选中TableView设置Content为static cell(静态单元格)

 

    2> 删除静态单元格, 只保留一个。

 

    3> 选中TableView设置style为grouped

 

    4> 选中单元格, 设置设置style为basic、设置Accessory为Disclosure Indicator。

 

    5> 双击"Title"设置文字.

 

    6> 选中单元格设置Image属性为: found_icons_qzone

    6.1> 选中 UITableView设置 style 为 Grouped

 

    7> 选中tableView设置Section为 3

 

    8> 选中第二个Section设置Rows为 2

 

    9> 选中第三个Section设置Rows为 3

 

 

    ** 注意: 当设置了数据源对象, 并且实现了数据源方法的时候, 即便有静态单元格也优先调用数据源方法来生成数据。

 

 

 

2. 动态加载"QQ好友列表"

 

    ** 步骤:

    1> 创建Group模型对象、Friend模型对象

    ** 注意, 加载数据时, 要把friends属性由"字典"集合转为"模型"集合。

 

    2> 懒加载数据

 

 

    3> 实现数据源方法, 显示好友列表数据(虽然可以使用系统默认的Cell, 但还是建议封装一个自定义Cell。)。

    ** 自定义一个Cell类继承自UITableViewCell类, 实现封装创建可重用单元格的代码以及一个模型属性。

    ** 这个自定义Cell中只使用到了Friend模型数据, 没有用到Group模型的相关内容, 所以只传递一个Friend模型到Cell中即可

 

 

    4> 设置分组的Header内容。

    * 演示: 先演示通过Storyboard的方式操作按钮的现实效果(左对齐、内边距等。)

    ** 注意: 虽然这里的每一组的子元素样子是一样的, 但是不能使用 xib 来实现, 因为 在 xib 中无法拖拽一个UITableViewHeaderFooterView控件, 所以依然需要完全自定义一个UITableViewHeaderFooterView类

    /**

        由于此时的Header View不再是普通文字了, 所以使用如下代理方法设置Header View

    

        (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section

     */

 

 

    ** 注意, 设置按钮内容水平左对齐

        //nameBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

 

    ** 注意, 设置按钮内容的内边距

        //btnGroupName.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);

 

    ** 注意, 设置标题文字与按钮中的ImageView之间的间距

        // btnGroupName.titleEdgeInsets= UIEdgeInsetsMake(0, 10, 0, 0);

 

    ** 注意, 设置按钮文字大小(加粗,18号)

        //btnGroupName.titleLabel.font = [UIFont boldSystemFontOfSize:18];

 

    ** 注意, 设置label文字右对齐

    // lblCount.textAlignment =NSTextAlignmentRight;

 

    ** 注意, 设置label文字为灰色

    // lblCount.textColor = [UIColorgrayColor];

 

    ** 注意, 在viewDidLoad中统一设置Section的行高:

    // self.tableView.sectionHeaderHeight = 44;

 

 

    5> 自定义UITableViewHeaderFooterViewe类。

    * 虽然这里的每一组的子元素样子是一样的, 但是不能使用 xib 来实现, 因为 在 xib 中无法拖拽一个UITableViewHeaderFooterView控件, 所以依然需要完全自定义一个UITableViewHeaderFooterView类

    * 在 viewDidLoad 方法中统一设置所有组的高度self.tableView.sectionHeaderHeight= 44;

 

    * 通过设置每一个UITableViewHeaderFooterViewe的 contentView 的背景色来观察每一个 header view。

 

 

 

    6> 点击展开、闭合分组

    * 思路:在TableView的数据源方法tableView:numberOfRowsInSection:中返回0, 则表示关闭。

        1> 为Group Header中的按钮注册单击事件

        2> 在Group模型中, 增加一个BOOL类型属性isVisible, 表示当前分组是否可见。(默认为NO

        3> 在用户单击事件中修改该属性的值为原来值得反面。isVisible = !isVisible

        4> 同时要想执行tableView:numberOfRowsInSection:方法, 必须重新reloadData。

    ** 注意: 如果全都设置了,但是点击就是没有效果,那么检查一下是不是忘记在set方法中为模型对象赋值了, 所以isVisible永远都是NO

        5> 局部刷新某组: 通过调用 tableView 的 reloadSections:方法来实现, 在 headerView 的 Tag中记录当前组的索引。

 

    /** 实现点击按钮, 打开\闭合组

        1. 为按钮注册单击事件

    

        2. 重写数据源方法中返回每个section的行个数的方法.

    

        3. 重新调用tableViewreloadData方法,(就会重新执行数据源方法, 就可以重新获取每个section的组的个数)

            ** 当这个section的组返回的个数是0的时候, 那么这个组看起来就"闭合".

    

        4. 在返回每个section的行的数据源方法中, 需要通过一个标记来判断当前应该返回0行还是实际的行数.

    

        5. headerView中无法直接刷新tableView, 需要通过代理来实现.

     */

 

 

    7> 旋转分组名称旁边的"三角图片"

    * 思路: 设置按钮中的ImageView旋转90度。通过transform

        1> 在按钮的单击事件中执行旋转:

        //self.btnGroupName.imageView.transform = CGAffineTransformMakeRotation(M_PI_2);

 

        2> 旋转无效?原因: 当tableView重新reloadData的时候, Header View被替换了, 变成了新的Header View。也就是说已经旋转了, 但是当reloadData的时候, 又产生了一个新的Header View, 所以看不到效果了。【解决: 在reloadData以后, 在新的Header View 加进来以后, 再执行旋转, 使用UIView的】

        **注意: 不能重用Header View的原因是调用了reloadData方法了。”重用Cell”、”重用headerView”指的是在滚动的时候重用。

        /** 参考代码:

         - (void)didMoveToSuperview

         {

             // 旋转

             if (self.group.isVisible) {

               self.btnGroupName.imageView.transform =CGAffineTransformMakeRotation(M_PI_2);

             } else {

               self.btnGroupName.imageView.transform =CGAffineTransformMakeRotation(0);

             }

         }

        

         */

 

        3> 旋转变形?原因: 按钮中的ImageView本身并没有发生大小改变, 当旋转的时候ImageView中的内容(图片)发生了旋转, 同时为了适应ImageView, 被拉伸了, 所以变形。【解决: 设置按钮中的ImageView的内容模式为"居中显示", 不拉伸】

        //btnGroupName.imageView.contentMode = UIViewContentModeCenter;

 

        4> 图片旋转后被裁减了? 原因: 当图片旋转后, 如果不自动缩放、拉伸, 会有部分内容超出ImageView, 那么此时imageView会自动不显示这部分内容。【解决: 设置ImageView不自动裁减】

        // btnGroupName.imageView.clipsToBounds= NO;

 

 

 

    8> 会员名字变成红色。

 

 

    9> 解决 header view 重用的时候, 按钮的三角图片显示不正常问题

    ** 在 setGroup 方法中重置单元格的图片旋转

    // 解决单元格重用的时候"小三角"图片旋转不正常的问题

    if (self.group.isVisible) {

        self.btnGroupTitle.imageView.transform= CGAffineTransformMakeRotation(M_PI_2);

    } else {

        self.btnGroupTitle.imageView.transform= CGAffineTransformMakeRotation(0);

    }

 

 

 

3. "App管理"案例。

** 知识点:

    1> 使用UITableView中的Cell来代替xib。(使用storyboard 中的 UITableView的 Cell 模板, 代替 xib)

    2> 循环利用Cell时的一个问题。(注意点: 在重用Cell之前,需要重新设置Cell的数据和状态。)

    3> 复习代理。(点击自定义Cell中的按钮, 在控制器中显示一个对话框)

 

** 步骤:

    1> 使用UITableViewController。

    2> 创建一个自定义个Tabe View 控制器类, 与控制器关联。

    3> 创建model

    4> 懒加载apps_full.plist数据。

    5> 实现数据源方法

    6> 系统默认Cell不足以显示app单元格, 每个行的Cell样子一样, 所以想到了用xib。但是这里使用另外一个东西来代替xib。就是UITableView中的cell.

    7> 创建一个自定义的cell类与storyboard中的Cell相关联。

    8> 修改TableView的行高为60.

    9> 为storyboard中的Cell指定一个identifier(重用ID)

    10> 在数据源方法中, 调用HMAppCell *cell = [tableViewdequeueReusableCellWithIdentifier:@"appcell"];来创建Cell。该方法首先从缓存池中查找对应的可重用Cell,如果没有则去storyboard中查找与identifier相同的Cell。

    11> 演示创建不同的Cell模板(需要为每个CEll指定不同的identifier),加载的时候根据不同的identifier来加载不同的Cell。

 

    /*** 参考代码: 加载storyboard中的cell的方式:

     - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {

    

         // 这个方法会先尝试从队列中查找,找不到则取storyboard中找identifier的值为@“appcell”的单元格。

         HMAppCell *cell = [tableViewdequeueReusableCellWithIdentifier:@“appcell”]

        

         cell.app = self.apps[indexPath.row];

        

         cell.delegate = self;

        

         return cell;

     }

    

     */

 

    12> 为自定义Cell类传递数据。

    13> 点击下载:

        1. 禁用下载按钮

        2. 显示"已下载"。通过代码或者设置Disabled状态下显示文字为"已下载"

        3. 弹出提示对话框。

    14> 解决循环利用Cell的时候"下载"按钮的状态问题。

        ** 注意: 当循环利用Cell的时候, 每次使用Cell前不仅要修改Cell的数据, 还要修改Cell状态。

        ** 在模型中增加一个BOOL类型属性donwloaded, 用来标记是否已经下载, 如果是, 则在设置数据的时候禁用该按钮,否则启用。

 

 

 

    /** 参考代码:

     在解决循环利用cell的那里补充:

     - (void)setApp:(HMApp *)app

     {

         _app = app;

        

         self.lblTitle.text = app.name;

         self.imgViewIcon.image = [UIImageimageNamed:app.icon];

         self.lblDownload.text = [NSStringstringWithFormat:@"大小:%@ | 下载量:%@", app.size,app.download];

        

         if (app.isDownloaded) {

             [self.btnDownload setTitle:@"已下载" forState:UIControlStateNormal];

             self.btnDownload.enabled = NO;

         } else {

             [self.btnDownload setTitle:@"下载" forState:UIControlStateNormal];

             self.btnDownload.enabled = YES;

         }

     }

 

     */

 

 

4. 作业: 新闻列表。演示功能

 

 

 

 

==================================其他需要注意点==================================

* 某个控件显示不出来可能的原因:

1. frame属性,是否为0,位置不对

2. hidden = YES

3. 是否添加到了父控件中

4. Alpha <= 0.01(当一个控件的透明度大于0.01的时候, 是可以监听事件的, 否则(<=0.01), 是无法监听事件的)

5. 被其他控件挡住了。

6. 检查父控件的上面这5种情况。

 

 

* 注意: 在重写layoutSubviews方法的时候, 不要忘记调用父类的layoutSubviews方法, 否则按钮点击无效果、不会切换normal与highlighted效果等。

// [superlayoutSubviews];

* 注意: layoutSubviews方法在当某个控件的frame发生改变时, 会自动调用。在这个方法中可以重新布局子控件。

 

* 提示: - (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section 设置每个Section的高度。

 

* 注意: 大多数UIView的子控件在执行init方法的时候或者刚执行完毕init方法的时候frame的值都是0, 需要我们手动来设置, 或者系统在某个时候自动设置。

 

/************************************************************************/

补充: 解释一个问题:为什么每次懒加载数据的时候都要创建一个新的NSMutableArray数组?原因是一开始属性是nil

/************************************************************************/

 

 

 

 

 

/************************************************************************/

其他补充内如:

 

授课内容: 静态单元格、自定义 UITableView 组的 header 和 footer

 

1. 静态单元格的使用

 

2. 自己抽象并创建plist 文件(根据需求抽象 plist 文件的能力)

 

3. 数据模型的嵌套

 

4.UITableViewHeaderFooterViewe类的使用

- 自定义组的 headerView 和 footerView

- 解决headerView 和 footerView 重用时的问题

 

5. layoutSubviews 方法介绍

 

6. 参考案例(案例使用自动布局实现): QQ 好友列表

 

 

7. 使用storyboard 中Cell 的模板来替代 xib 实现 自定义Cell

- 参考案例:"通过 UITableView 实现App管理"

 

/************************************************************************/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值