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

疯狂Java联盟

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

[iOS] 处理单元格的选中(Swift和OC双语)——表格与表格控制器...

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

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




当表格控件允许选中时,在默认情况下,当用户单击表格的某个表格行时,系统就会选中对应的表格行。UITableView提供了allowsSelection、allowsMultipleSelection、allowsSelectionDuringEditing、allowsMultipleSelectionDuringEditing属性来配置表格的选中状态。
UITableView还提供的如下方法来操作表格中被选中的行。
q     - indexPathForSelectedRow:获取选中表格行对应的NSIndexPath
q     - indexPathsForSelectedRows:获取所有被选中的表格行对应的NSIndexPath组成的数组。
q     -selectRowAtIndexPath:animated:scrollPosition::控制该表格选中指定NSIndexPath对应的表格行,最后一个参数控制是否滚动到被选中行的顶端、中间和底部。
q     -deselectRowAtIndexPath:animated::控制取消选中该表格中指定NSIndexPath对应的表格行。
如果程序需要响应表格行的选中事件,那么就需要借助UITableView的委托对象,委托对象必须实现UITableViewDelegate协议——当UITableView的表格行发生选中相关事件时,都会激发该委托对象的响应方法。UITableViewDelegate中定义了如下方法。
q     -tableView:willSelectRowAtIndexPath::当用户将要选中表格中的某行时激发该方法。
q     -tableView:didSelectRowAtIndexPath::当用户完成选中表格中的某行时激发该方法。
q     - tableView:willDeselectRowAtIndexPath::当用户将要取消选中表格中的某行时激发该方法。
q     -tableView:didDeselectRowAtIndexPath::当用户取消选中表格中的某行时激发该方法。
实例:编辑选中行
下面通过选中某个表格行进入编辑状态,用户可以在编辑界面对指定表格行数据进行编辑,编辑完成后即可再次返回表格界面。
首先创建一个“Single ViewApplication”应用,然后使用代码向界面上创建、并添加UITableView控件,然后使该控件与整个屏幕大小相同。
为了给应用程序提供显示、修改的数据,此处为应用程序委托类定义两个可变的Array集合,这两个Array集合相当于模拟了内存中的数据库。
下面是应用程序委托类的代码。
程序清单:codes/11/11.2/SelectCellTest/SelectCellTest/AppDelegate.swift
class AppDelegate: UIResponder,UIApplicationDelegate {
         varwindow: UIWindow?
         varbooks: [String]!
         vardetails: [String]!
         funcapplication(application: UIApplication, didFinishLaunchingWithOptions
                   launchOptions:[NSObject: AnyObject]?) -> Bool {
                   //创建并初始化Array对象
                   self.books= ["疯狂Android讲义",
                            "疯狂iOS讲义", "疯狂Ajax讲义" , "疯狂Swift讲义"]
                   self.details= ["长期雄踞各网店销量排行榜榜首的图书",
                            "全面而详细的iOS开发图书",
                            "Ajax开发图书" ,
                            "系统介绍Swift相关知识"]
                   returntrue
         }
         ...
}
本例使用控制器对象作为UITableView控件的dataSource和delegate对象,因此该控制器类需要实现UITableViewDataSource和UITableViewDelegate协议。
视图控制器类主要就是根据AppDelegate的books、details两个Array集合的数据来实现UITableViewDataSource协议中两个必需的方法——这部分基本与前一个示例相同。除此之外,程序还需要让该控制器类实现UITableViewDelegate协议中定义的tableView:didSelectRowAtIndexPath:方法——当用户选中指定的表格行时将会激发委托的该方法。下面是视图控制器类的代码。
程序清单:codes/11/11.2/SelectCellTest/SelectCellTest/ViewController.swift
import UIKit

// 为表格行定义一个静态字符串作为标识符
let cellId = "cellId"
class ViewController: UIViewController ,UITableViewDataSource, UITableViewDelegate{
         vartable: UITableView!
         varappDelegate: AppDelegate!
         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)
                   //UITableView控件设置dataSourcedelegate
                   self.table.dataSource= self
                   self.table.delegate= self
                   appDelegate= UIApplication.sharedApplication().delegate as! AppDelegate
         }
         overridefunc viewWillAppear(animated:Bool) {
                   super.viewWillAppear(animated)
                   self.table.reloadData()
         }
         // 该方法返回值决定各表格行的控件
         functableView(tableView: UITableView,
                   cellForRowAtIndexPathindexPath: NSIndexPath) -> UITableViewCell {
                   //从可重用表格行队列中取出一个表格行
                   varcell = tableView.dequeueReusableCellWithIdentifier(cellId)
                   //如果取出的表格行为nil
                   ifcell == nil {
                            //创建一个UITableViewCell对象,使用默认风格
                            cell= UITableViewCell(style: .Subtitle, reuseIdentifier: cellId)
                            // 将单元格的边框设置为圆角
                            cell?.layer.cornerRadius = 12
                            cell?.layer.masksToBounds = true
                            // UITableViewCell的左端设置图片
                            cell?.imageView?.image = UIImage(named:"ic_gray.png")
                            // UITableViewCell的左端设置高亮状态的图片
                            cell?.imageView?.highlightedImage =UIImage(named:"ic_highlight.png")
                   }
                   //IndexPath参数中获取当前行的行号
                   letrowNo = indexPath.row
                   //取出books中索引为rowNo的元素作为UITableViewCell的文本标题
                   cell?.textLabel?.text= appDelegate.books[rowNo]
                   //取出details中索引为rowNo的元素作为UITableViewCell的详细内容
                   cell?.detailTextLabel?.text= appDelegate.details[rowNo]
                   returncell!
         }
         // 该方法的返回值决定指定分区内包含多少个表格行
         functableView(tableView: UITableView,
                   numberOfRowsInSectionsection: Int) -> Int{
                   //由于该表格只有一个分区,直接返回books中集合元素个数代表表格的行数
                   returnappDelegate.books.count;
         }
         func tableView(tableView: UITableView,
                   didSelectRowAtIndexPathindexPath: NSIndexPath) {
                   // 获取Storyboard文件中IDdetail的视图控制器
                   let detailController =self.storyboard?.instantiateViewControllerWithIdentifier("detail")
                            as?DetailViewController
                   // 保存用户正在编辑的表格行对应的NSIndexPath
                   detailController!.editingIndexPath= indexPath
                   // 显示detailViewController
                   self.showViewController(detailController!,sender: self)
         }
}
上面实现类最大的变化在于其中用粗体字表示的方法,当用户选中某个表格行时,将会激发该粗体字方法——该方法将会使用editingIndexPath保存用户正在编辑的表格行信息,接下来程序调用了视图控制器的showViewController: sender:方法来显示detailViewController,这就实现了界面切换。
提示:除了上面程序的这种界面切换方式之外,iOS还推荐使用segueUINavigationController控制界面切换,只是此处暂未介绍segueUINavigationController的用法,因此暂时使用这种方式进行切换。
上面粗体字代码对应的Objective-C版本如下:
程序清单:codes/11/11.2/SelectCellTest_OC/SelectCellTest_OC/ViewController.m
- (void)tableView:(UITableView *)tableView
         didSelectRowAtIndexPath:(NSIndexPath*)indexPath{
         // 获取Storyboard文件中IDdetail的视图控制器
         DetailViewController*detailController = [self.storyboard
                   instantiateViewControllerWithIdentifier:@"detail"];
         // 保存用户正在编辑的表格行对应的NSIndexPath
         detailController.editingIndexPath= indexPath;
         // 显示detailViewController
         [selfshowViewController:detailController sender: self];
}
程序中的粗体字代码控制当用户单击指定的表格行时,应用窗口会加载、显示Storyboard文件中ID为detail的控制器,因此程序需要在Storyboard中添加一个场景,从Xcode右下角的库面板中将一个UIViewController拖入Main.storyboard文件中,此时Main.storyboard将包含两个视图控制器。
在选中新添加视图控制器的前提下,按下“command+option+3”快捷键打开身份检查器面板,先在Class文本框中输入DetailViewController,此处用于指定该视图控制器对应的类。然后在Storyboard ID文本框中输入detail,如图11.11所示——该字符串将作为该视图控制器的ID。UIStoryboard对象可根据该ID字符串来加载该视图控制器。

11.11 为视图控制器设置ID
接下来还需要建立控制器类用于编辑表格行数据,可以单击Xcode的“File”→“New”→“File...”菜单来新建文件,然后选择新建iOS中Source分类下的“Cocoa Touch Class”,最后单击“Next”按钮,即可看到如图11.12所示的界面。

11.12 创建视图控制器
从图11.12中可以看出,只要新建的类继承了UIViewController,即表明将要创建一个控制器。按图11.12所示的方式输入视图控制器的名称,不要勾选对话框下方的“Also create XIB file”复选框(因为此项目使用了Storyboard界面设计文件,XIB界面设计文件已经过时),再单击“Next”按钮,Xcode显示选择保存路径对话框,为DetailViewController类选择保存路径后,单击“Create”按钮即可完成创建。
为了可以在程序界面上修改选中表格行的数据,程序需要使用代码在向该界面添加两个文本框,为了让两个文本框编辑完成时可关闭键盘,还需要为两个文本框的Did End On Exit事件绑定finished:事件处理方法。
除此之外,为了让程序可以通过返回前一个视图控制器,程序还将为该界面添加一个工具条,该工具条上将会包含一个“完成”按钮,用于告诉通知系统完成编辑、返回前一个视图控制器。
该视图控制器还需要定义一个editingIndexPath属性,用于记录当前正在编辑的表格行。下面是DetailViewController类的代码。
程序清单:codes/11/11.2/SelectCellTest/SelectCellTest/DetailViewController.swift
import UIKit

class DetailViewController: UIViewController {
         varnameField: UITextField!
         vardetailField: UITextField!
         vareditingIndexPath: NSIndexPath!
         varappDelegate: AppDelegate!
         varrowNo: Int!
         overridefunc viewDidLoad() {
                   super.viewDidLoad()
                   //下面省略了创建、添加界面控件的代码
                   ...
         }
         // 当该视图将要显示出来时调用该方法
         overridefunc viewWillAppear(animated: Bool) {
                   super.viewWillAppear(animated)
                   appDelegate= UIApplication.sharedApplication().delegate as? AppDelegate
                   //获取正在编辑的表格行的行号
                   rowNo= self.editingIndexPath.row
                   //nameFielddetailFieldtext赋值
                   self.nameField.text =appDelegate.books[rowNo]
                   self.detailField.text =appDelegate.details[rowNo]
         }
         functapped(sender: AnyObject) {
                   //替换_appDelegatebooks集合中指定索引处的元素
                   appDelegate.books[rowNo] =self.nameField.text!
                   //替换_appDelegatedetails集合中指定索引处的元素
                   appDelegate.details[rowNo] =self.detailField.text!
                   //取消显示当前视图控制器
                   self.dismissViewControllerAnimated(true,completion: nil)
         }
         funcfinished(sender: AnyObject) {
                   //sender放弃作为第一响应者
                   sender.resignFirstResponder()
         }
}
在上面的程序中,前两行粗体字代码获取用户选中的表格行的数据,并将这些数据显示在该界面的nameField和detailField中;接下来的tapped:事件处理方法中4行粗体字代码使用用户输入的文本替换books、details集合中指定索引处的元素,然后取消现实当前视图控制器——这样即可再次返回表格视图。
该程序中tapped:事件处理方法对应Objective-C版本如下:
程序清单:codes/11/11.2/SelectCellTest_OC/SelectCellTest_OC/DetailViewController.m
-(void) tapped:(id)sender {
         // 替换_appDelegatebooks集合中指定索引处的元素
         [_appDelegate.booksreplaceObjectAtIndex:_rowNo
                   withObject:self.nameField.text];
         // 替换_appDelegatedetails集合中指定索引处的元素
         [_appDelegate.detailsreplaceObjectAtIndex:_rowNo
                   withObject:self.detailField.text];
         // 取消显示当前视图控制器
         [selfdismissViewControllerAnimated:true completion:nil];
}
编译、运行该程序,单击表格中指定的表格行,即可看到如图11.13所示的界面。
11.13.png

11.13 编辑表格行数据
在图11.13所示的界面中对表格行数据进行编辑,编辑完成后单击“完成”按钮,程序就会用用户输入的内容替换books和details集合中指定索引处的元素,修改后的表格数据如图11.14所示。
11.14.png

11.14 修改后的表格数据

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

本版积分规则

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

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

GMT+8, 2019-8-24 22:59 , Processed in 0.311857 second(s), 7 queries , File On.

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