请选择 进入手机版 | 继续访问电脑版
本站特色:极好的技术研究氛围!所有技术交流,必有回复!

疯狂Java联盟

 找回密码
 加入联盟
查看: 677|回复: 0

[iOS] 定制表格行(Swift和OC双语)——表格与表格控制器之四

[复制链接]
发表于 2017-11-20 19:36:02 | 显示全部楼层 |阅读模式
本帖最后由 kongyeeku 于 2017-11-21 11:34 编辑

本文节选自《疯狂iOS讲义(基础篇)》。




如果只是使用系统提供的UITableViewCell,UITaleView控件的表格行只支持有限的样式,而且每个表格行只包含textLabel、detailTextLabel、UIImageView这三个控件。因此,开发者无法自由地对表格行进行定制。
为了自由地定制UITableView控件的表格行(比如让表格行显示更多的控件,让表格行显示更丰富的格式等),可通过如下方式来完成。
q     继承UITableViewCell定制表格行。开发者可通过继承UITableViewCell来添加任意控件,设置任意样式。
q     使用动态单元格原型定制表格行。这种方式非常方便,开发者直接在Interface Builder中设计表格行的样式即可。
下面分别介绍这两种方式的实例。
实例1:继承UITableViewCell定制表格行
继承UITableViewCell之后,可以向UITableViewCell中添加任意控件,即可实现对表格行的定制。
首先创建一个“Single ViewApplication”应用,使用代码创建、并添加UITableView控件,并使该控件与整个屏幕大小相同。
本例使用控制器对象作为UITableView控件的dataSource和delegate对象,因此,该控制器类需要实现UITableViewDataSource和UITableViewDelegate协议。
接下来修改该控制器类,该实例的代码与前面示例的代码大致相似,只是该控制器类所实现的tableView:cellForRowAtIndexPath:方法将会返回自定义表格行,而不是返回默认的UITableViewCell对象。下面就是控制器类的代码。
程序清单:codes/11/11.2/ExtendCellTest/ExtendCellTest/ViewController.swift
import UIKit

// 为表格行定义一个静态字符串作为标识符
let cellId = "cellId"
class ViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
         varbooks : [String]!
         varprices : [String]!
         vartable: UITableView!
         overridefunc viewDidLoad() {
                   super.viewDidLoad()
                   //创建、添加一个UITableView
                   letsize = self.view.bounds.size
                   self.table= UITableView(frame: CGRectMake(0 , 20 ,
                            size.width,size.height - 20) , style: .Plain)
                   self.view.addSubview(self.table)
                   //创建并初始化NSArray对象
                   books= ["疯狂Android讲义", "疯狂iOS讲义", "疯狂Ajax讲义",
                            "疯狂Swift讲义"]
                   //创建并初始化NSArray对象
                   prices= ["108", "99" , "79" , "69"]
                   //UITableView控件设置dataSourcedelegate
                   self.table.dataSource= self;
                   self.table.delegate= self;
         }
         // 该方法的返回值决定各表格行的控件
         functableView(tableView: UITableView,
                   cellForRowAtIndexPathindexPath: NSIndexPath) -> UITableViewCell {
                   //从可重用表格行队列中取出一个表格行
                   var cell =tableView.dequeueReusableCellWithIdentifier(cellId) as! BookTableCell!
                   //如果取出的表格行为nil,创建、并初始化单元格
                   ifcell == nil {
                            //创建自定义的BookTableCell对象
                            cell= BookTableCell(style:.Default, reuseIdentifier:cellId)
                            // 将单元格的边框设置为圆角
                            cell.layer.cornerRadius= 12
                            cell.layer.masksToBounds= true
                   }
                   //IndexPath参数中获取当前行的行号
                   letrowNo = indexPath.row
                   //为表格行的nameFieldpriceFieldtext设置值
                   cell.nameField?.text= books[rowNo]
                   cell.priceField?.text= prices[rowNo]
                   returncell;
         }
         // 该方法的返回值决定指定分区内包含多少个表格行
         functableView(tableView: UITableView,
                   numberOfRowsInSectionsection: Int) -> Int{
                   //由于该表格只有一个分区,直接返回_books中集合元素个数代表表格的行数
                   returnbooks.count
         }
         // 该方法的返回值将作为表格行的高度
         func tableView(tableView: UITableView,
                   heightForRowAtIndexPathindexPath: NSIndexPath) -> CGFloat {
                   return 60
         }
}
上面程序中tableView: cellForRowAtIndexPath:方法中粗体字代码负责创建一个自定义的BookTableCell控件作为表格行控件,而不是使用默认的UITableViewCell作为表格行控件。而BookTableCell继承了UITableViewCell,开发者可以对BookTableCell进行任意定制,从而自由地定制UITableView的表格行控件。
除此之外,上面的控制器类还实现了tableView:heightForRowAtIndexPath:方法,该方法所返回的CGFloat值用于决定表格行的高度。
上面程序中tableView:cellForRowAtIndexPath:方法对应的Objective-C版本如下:
程序清单:codes/11/11.2/ExtendCellTest_OC/ExtendCellTest_OC/ViewController.m
// 该方法的返回值决定各表格行的控件
- (UITableViewCell *)tableView:(UITableView*)tableView
                   cellForRowAtIndexPath:(NSIndexPath *)indexPath {
         // 为表格行定义一个静态字符串作为标识符
         staticNSString* cellId = @"cellId";
         // 从可重用表格行队列中取出一个表格行
         BookTableCell*cell = [tableView dequeueReusableCellWithIdentifier:cellId];
         // 如果取出的表格行为nil
         if(cell== nil) {
                   //创建自定义的BookTableCell对象
                   cell= [[BookTableCell alloc] initWithStyle:
                            UITableViewCellStyleDefaultreuseIdentifier:cellId];
                  // 将单元格的边框设置为圆角
                  cell.layer.cornerRadius = 12;
                  cell.layer.masksToBounds = YES;
         }
         // IndexPath参数中获取当前行的行号
         NSUIntegerrowNo = indexPath.row;
         // 为表格行的nameFieldpriceFieldtext设置值
         cell.nameField.text= _books[rowNo];
         cell.priceField.text= _prices[rowNo];
         returncell;
}
上面程序中用到了BookTableCell,因此还需要定义BookTableCell类,通过单击Xcode的“File”→“New”→“File…”菜单,在打开的对话框中选择iOS的Source分类中的“Cocoa Touch Class”,即可开始创建Swift或Objective-C类,为新建的Cocoa Touch类选择UITableViewCell作为父类。
在BookTableCell类的中定义nameLabel和priceLabel两个属性,以方便程序访问该表格行中的这两个UI控件。BookTableCell类的关键就是重写该类的initWithStyle: reuseIdentifier:方法,在该方法中可以添加任意的UI控件,即可对界面进行任意定制。下面是BookTableCell类的代码。
程序清单:codes/11/11.2/ExtendCellTest/ExtendCellTest/BookTableCell.swift
import UIKit

class BookTableCell: UITableViewCell {
         varnameField : UILabel!
         varpriceField : UILabel!
         overrideinit(style: UITableViewCellStyle, reuseIdentifier: String?) {
                   super.init(style:style, reuseIdentifier:reuseIdentifier)
                   letbgColor = UIColor(red:0.7, green:1.0, blue:0.7, alpha: 1.0)
                   self.contentView.backgroundColor= bgColor;  // 设置使用淡绿色背景
                   //创建一个用于显示"书名"字符串的标签
                   letnameLabel = UILabel(frame:CGRectMake(5, 5, 70, 20))
                   nameLabel.text= "书名:"  // 设置该UILabel显示的文本内容
                   nameLabel.textAlignment= NSTextAlignment.Right  // 设置右对齐
                   nameLabel.font= UIFont.boldSystemFontOfSize(17)  // 设置字体
                   nameLabel.backgroundColor= UIColor.clearColor()  // 设置背景色
                   //nameLabel添加到当前单元格中
                   self.contentView.addSubview(nameLabel)
                   //创建一个用于显示"价格"字符串的标签
                   letpriceLabel = UILabel(frame:CGRectMake(5, 30, 70, 20))
                   priceLabel.text= "价格:"  // 设置该UILabel显示的文本内容
                   priceLabel.textAlignment= NSTextAlignment.Right  // 设置右对齐
                   priceLabel.font= UIFont.boldSystemFontOfSize(17)  // 设置字体
                   priceLabel.backgroundColor= UIColor.clearColor()  // 设置背景色
                   self.contentView.addSubview(priceLabel)  // priceLabel添加到当前单元格中
                   //创建一个用于显示书名值的标签
                   self.nameField= UILabel(frame:CGRectMake(90, 5, 180, 20))
                   self.nameField.textAlignment= NSTextAlignment.Left  // 设置左对齐
                   self.nameField.font= UIFont.boldSystemFontOfSize(18)  // 设置字体
                   self.nameField.textColor= UIColor.blueColor()  // 设置文字颜色
                   //self.nameField添加到当前单元格中
                   self.contentView.addSubview(self.nameField)
                   //创建一个用于显示价格值的标签
                   self.priceField= UILabel(frame:CGRectMake(90, 30, 180, 20))
                   self.priceField.textAlignment= NSTextAlignment.Left  // 设置左对齐
                   self.priceField.font= UIFont.boldSystemFontOfSize(18)  // 设置字体
                   self.priceField.textColor= UIColor.blueColor()  // 设置文字颜色
                   //self.priceField添加到当前单元格中
                   self.contentView.addSubview(self.priceField)
         }
         requiredinit?(coder aDecoder: NSCoder) {
                   fatalError("init(coder:)has not been implemented")
         }
}
上面程序重写了initWithStyle:reuseIdentifier:方法就是向表格行中添加4个UILabel,其中两个UILabel显示固定的字符串,两个UILabel显示动态的表格数据。
上面BookTableCell类的代码主要就是创建、并添加UI控件,没有任何特别之处,故此处不再给出该类的Objective-C版本,读者可参考光盘代码。
编译、运行该程序,即可看到如图11.15所示的表格。
11.15.png

11.15 继承UITableViewCell自定义表格行
从图11.15中可以看出,此时每个表格行包含4个UILabel,其中两个UILabel显示固定的字符串,另外两个UILabel显示表格数据。由此可见,通过继承UITableViewCell,即可自由地定制UITableView控件的表格行。
实例2:使用动态单元格原型定制表格行
如果采用继承UITableViewCell的方式来定制表格行,那么UITableViewCell的子类在重写initWithStyle:reuseIdentifier:方法时需要大量的代码来定制表格行界面——如本节实例1所示。如果程序需要定制更复杂的表格行,那么initWithStyle: reuseIdentifier:方法需要的代码量就更多了。
Storyboard允许开发者直接在UITableView中设计单元格的外观,只要通过为UITableView指定动态单元格原型即可以可视化方式设计单元格。下面例子将会示范这种开发方式。
将一个UITableView拖入界面设计文件中,为了在程序中访问该UITableView控件,还需要将该控件绑定到视图控制器的tableViewIBOutlet属性。
选中新添加的UITableView,然后打开Xcode的属性检查器面板,将Content列表框设为“Dynamic Prototypes”(表明使用动态单元格原型),并将PrototypeCells设为“2”(表明设计两个动态单元格原型),如图11.16所示。
11.16.png

11.16 设置使用动态单元格原型
此处指定使用两个表格行原型,因此图11.16中有两个空白行,开发者可以通过该空白行来设计该表格的表格行原型,可以按业务需求向该表格行原型中添加任意的UI控件(一定要拖入表格行原型内)。编辑表格行原型时要注意如下两点。
q     为表格行原型的Identifier指定一个字符串属性值(选中该表格行原型,打开属性检查器面板即可设置Identifier属性)——就像前面介绍的UITableView一样,iOS需要为表格行原型指定一个Identifier属性值。
q     同一个表格行原型内添加的所有UI控件需要指定互不相同的Tag属性值,从而保证应用程序代码可以获取这些UI控件。
将两个表格行原型的Identifier分别指定为cell1、cell2,向两个表格行原型中各添加一个UILabel控件和UIImageView控件,将两个表格行中UILabel的字体设置成不同的颜色以示区分,并将两个UILabel的Tag设为1——虽然两个UILabel的Tag属性值相同,但它们位于不同的父容器中,因此程序可以正常区分并获取它们。
提示:如果有需要,完全可以向该表中添加更多的表格行,此处添加的每个表格行都将会作为表格行原型,程序可以控制该表格显示很多行,每个表格行都可根据需要使用指定的表格行原型。
表格行原型设计完成后,可以看到如图11.17所示的界面。
11.17.png

11.17 设计表格行原型
通过Storyboard为UITableView设计表格行原型之后,接下来开发的UITableView控件就更简单了:程序直接使用这些表格行原型即可。
下面是该实例的视图控制器类的代码。
程序清单:codes/11/11.2/DynaCell/DynaCell/ViewController.swift
import UIKit

class ViewController: UIViewController,UITableViewDataSource {
         varbooks : [String]!
         @IBOutletvar tableView: UITableView!
         overridefunc viewDidLoad() {
                   super.viewDidLoad()
                   self.tableView.dataSource= self
                   books= ["疯狂Android讲义", "疯狂iOS讲义", "疯狂Ajax讲义",
                            "疯狂Swift讲义"]
         }
         functableView(tableView: UITableView,
                   numberOfRowsInSectionsection: Int) -> Int{
                   returnbooks.count
         }
         functableView(tableView: UITableView, cellForRowAtIndexPath
                   indexPath:NSIndexPath) -> UITableViewCell {
                   let rowNo =indexPath.row  // 获取行号
                   // 根据行号的奇偶性使用不同的标识符
                   let identifier = rowNo % 2 ==0 ? "cell1" : "cell2"
                   // 根据identifier获取表格行(identifier要么是cell1,要么是cell2
                   let cell =tableView.dequeueReusableCellWithIdentifier(
                                     identifier,forIndexPath:indexPath)
                   // 获取cell内包含的Tag1UILabel
                   let label =cell.viewWithTag(1) as? UILabel
                   label?.text = books[rowNo]
                   return cell
         }
}
从上面的粗体字代码可以看出,该方法只要根据表格行原型的Identifier属性,即可获取该表格行控件,接下来就可以获取该表格行所包含的子控件,剩下的代码修改这些子控件的内容即可。
上面程序中重写的tableView:cellForRowAtIndexPath:方法对应的Objective-C版本如下:
程序清单:codes/11/11.2/DynaCell_OC/DynaCell_OC/ViewController.m
- (UITableViewCell *)tableView:(UITableView*)tableView
         cellForRowAtIndexPath:(NSIndexPath*)indexPath {
         NSIntegerrowNo = indexPath.row;  // 获取行号
         // 根据行号的奇偶性使用不同的标识符
         NSString*identifier = rowNo % 2 == 0 ? @"cell1" : @"cell2";
         // 根据identifier获取表格行(identifier要么是cell1,要么是cell2
         UITableViewCell*cell = [tableView dequeueReusableCellWithIdentifier:
                            identifier forIndexPath:indexPath];
         // 获取cell内包含的Tag1UILabel
         UILabel*label = (UILabel*)[cell viewWithTag:1];
         label.text= _books[rowNo];
         returncell;
}
编译、运行该程序,可以看到如图11.18所示的界面。
11.18.png

11.18  使用动态单元格原型的表格

您需要登录后才可以回帖 登录 | 加入联盟

本版积分规则

视频、代码、电子书下载
请关注"疯狂图书"公众号
QQ交流1群: 545923995  未满
微信群请扫二维码
QQ交流1群:
545923995
(未满)

小黑屋|手机版|Archiver|疯狂Java联盟 ( 粤ICP备11094030号 )

GMT+8, 2019-5-22 19:43 , Processed in 0.360336 second(s), 7 queries , File On.

快速回复 返回顶部 返回列表