这篇会很长,因为UITableView很重要,几乎处处会见到它的影子。
一、UITableView的简单介绍
1、表视图的组成
表头 表脚 单元格 节 ,当然节 也分为节头 节脚 可以显示节的信息或者声明
2、表视图的相关类
UITableView 继承自UIScrollView,有两个协议 UITableViewDelegate 委托协议
和UITableViewDataSource 数据源协议 ,表视图对应的UITableViewController控制器,UITableViewCell 单元格 ,UITableViewHeaderFooterView 为节头节脚提供视图
3、表视图的分类
普通表视图:跟Android中的最简单listView实现一样,或者可以说只有一个节就能完全表示数据
分组表视图:分为很多个节,每个节中的单元格相似或者不一样,还有索引表视图、选择表视图(ios中没有多选框)、搜索栏表视图、分页表视图
4、单元格的组成
单元格由 图标、标题 、副标题 和扩展视图组成
5、数据源协议和委托协议
不详细说,看代码中注释吧
6、UITableViewController 视图控制器
我们原来都是直接继承UIViewController ,视图最外层是 UIView 是我们的父容器,例如:我们学习的UICollectionView ,我们把集合视图放进到UIView中去,其实我们还可以直接 让我们的ViewController 继承UICollectionViewController,这样我们的最外层容器就是UICollectionView才行,这样的好处是减少了视图的嵌套,减少了代码量,因为UICollectionViewController 会实现其相对应的委托协议和数据源协议,同样的道理我们可以直接使用UITableViewController来实现我们的控制器,这样最外层必须是UITableView,当然这一切的前提是界面上除了UITableView,不再需要其他控件了
二、简单的实现一个普通表视图
我们直接使用UITableViewController,在故事版中删除原有的ViewController,我们拖进去一个
选中
就可以表明该视图是初始视图控制器
更改
控制器是指向我们自己的控制器,这个控制器是继承UITableViewController的,这里我修改的时候有时候无法修改,不知道咋回事,必须给ViewController改改名字才能在这里改,不知道啥情况。。。
然后给单元格加上复用标签
这就好了,接下来看控制器代码
import UIKit
class ViewControllerTable: UITableViewController {
var data:NSArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//初始化数据
let pathList=Bundle.main.path(forResource: "team", ofType: "plist")
self.data=NSArray.init(contentsOfFile: pathList!)
}
//重写数据源协议
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//故事版实现时,复用单元格时,使用该方法
let cell=tableView.dequeueReusableCell(withIdentifier: "cellIndentifier", for: indexPath)
let row=indexPath.row
let rowDic=self.data[row] as! NSDictionary
let imagePath=String.init(format: "%@.png", (rowDic.value(forKey: "image") as? String)!)
cell.imageView?.image=UIImage.init(named: imagePath)
cell.textLabel?.text=rowDic.value(forKey: "name") as? String
//指定扩展视图的样式
cell.accessoryType = .disclosureIndicator
return cell
}
}
纯代码实现:不使用 故事版文件代码 如下:
import UIKit
//控制器设为UITableViewController 控制器
class ViewController: UITableViewController {
var data:NSArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//初始化数据
let plistPath=Bundle.main.path(forResource: "team", ofType: "plist")
self.data=NSArray.init(contentsOfFile: plistPath!)
}
//实现数据源协议 返回节中的单元格数
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.data.count
}
//返回单元格视图
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//是否有可以复用的单元格
var cell:UITableViewCell!=tableView.dequeueReusableCell(withIdentifier: "CellIdentifier")
if(cell==nil){
// 创建单元格,设定单元格的样式是默认,添加复用标记
cell=UITableViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: "CellIdentifier")
}
let row=indexPath.row
let itemData=self.data[row] as! NSDictionary
let imagePath=String.init(format: "%@.png", (itemData.value(forKey: "image")) as! String )
cell.imageView?.image=UIImage.init(named: imagePath)
cell.textLabel?.text=itemData.value(forKey: "name") as? String
//扩展视图的按钮样式
cell.accessoryType = .disclosureIndicator
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
三、自定义单元格
单元格虽然有几个自带的样式,但是有时候肯定无法满足我们的需求,这个时候就需要自己定义了,首先看故事版自定义如何实现:
很简单直接往单元格里面拖拽自己想定义的控件即可,
然后创建自定义单元格继承UITableCell
然后修改故事版中单元格属于自定义单元格所属的类
然后打开辅助视图,让故事版单元格中的控件和自定义单元格类互相绑定即可,其他代码里面有注释
单元格类
import UIKit
class TableViewCell: UITableViewCell {
//绑定故事版中的相应控件
@IBOutlet weak var myImage: UIImageView!
@IBOutlet weak var name: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//这里必须加 否则会报异常 加载故事版 或者 xib文件 必须使用
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
控制器:
import UIKit
class ViewControllerTable: UITableViewController {
var data:NSArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let plistPath=Bundle.main.path(forResource: "team", ofType: "plist")
self.data=NSArray.init(contentsOfFile: plistPath!)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//注意这里的类型使我们自定义的单元格类型 其他的跟原来一样
let cell:TableViewCell=tableView.dequeueReusableCell(withIdentifier: "CellIdentifier", for: indexPath) as! TableViewCell
let row=indexPath.row
let itemData:NSDictionary=self.data[row] as! NSDictionary
let imagePath=String.init(format: "%@.png", (itemData.value(forKey: "image")) as! String)
cell.myImage.image=UIImage.init(named: imagePath)
cell.name.text=itemData.value(forKey: "name") as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
下面看不用故事版用纯代码构建:
import UIKit
class myTableViewCell: UITableViewCell {
var myImage:UIImageView!
var name:UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
//添加控件
let cH:CGFloat=self.frame.size.height
let cW:CGFloat=self.frame.size.width
self.name=UILabel.init(frame: CGRect(x: 10,y: (cH-31)/2,width: 100, height:31))
self.name.contentMode = .scaleAspectFill
self.name.textAlignment = .left
self.addSubview(self.name)
let imageH:CGFloat=31
let imageW:CGFloat=57
self.myImage=UIImageView.init(frame: CGRect(x: cW-imageW-30,y: (cH-imageH)/2,width: imageW, height: imageH ))
self.addSubview(self.myImage)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
控制器:
import UIKit
class ViewController: UITableViewController {
var data:NSArray!
override func viewDidLoad() {
super.viewDidLoad()
let plistPath:String!=Bundle.main.path(forResource: "team", ofType: "plist")
self.data=NSArray.init(contentsOfFile: plistPath)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:myTableViewCell! = tableView.dequeueReusableCell(withIdentifier: "CellIdentifier") as? myTableViewCell
if(cell==nil){
cell=myTableViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: "CellIdentifier")
cell.accessoryType = .disclosureIndicator
}
let row=indexPath.row
let itemData=self.data[row] as! NSDictionary
let imagePath=String.init(format: "%@.png", ((itemData.value(forKey: "image")) as? String)!)
cell.myImage.image = UIImage.init(named: imagePath)
cell.name.text = itemData.value(forKey: "name") as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
比较简单,不在啰嗦
四、添加搜索栏
搜索栏做手机开发的肯定经常见到,搜索栏对应一个UISearchController,如果我们想使用这个控制器就必须代码实现了,因为我们目前是使用UITableViewController来实现表视图的,用搜索栏的控制器来实现比较方便简单,当然我们也可以直接在故事版文件中拖拽一个,然后设置它的属性
但是不建议这么做,我们使用控制器来实现
最后的效果图:
直接看控制器代码:
//
// ViewController.swift
// P6UITableViewBuild
//
// Created by LF on 2017/4/5.
// Copyright © 2017年 yinwei. All rights reserved.
//
import UIKit
//继承表视图控制器,实现搜索栏委托协议
class ViewControllerTable: UITableViewController,UISearchBarDelegate,UISearchResultsUpdating {
var data:NSArray!
//过滤后的数据
var filterData:NSMutableArray!
//声明UISearchController
var searchController:UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//初始化数据
let pathList=Bundle.main.path(forResource: "team", ofType: "plist")
self.data=NSArray.init(contentsOfFile: pathList!)
//初次查询所有数据
self.filterContentForSearchText(searchText: "",scope: -1)
//实例化UISearchController 只能由代码实现
self.searchController=UISearchController.init(searchResultsController: nil)
//设置本身为搜索结果的对象
self.searchController.searchResultsUpdater=self
//在搜索时 设置背景为黑色
self.searchController.dimsBackgroundDuringPresentation=false
//设置搜索范围栏中的按钮
self.searchController.searchBar.scopeButtonTitles=["中文","英文"]
self.searchController.searchBar.delegate=self
//将搜索栏放到表视图的表头中
self.tableView.tableHeaderView=self.searchController.searchBar
self.searchController.searchBar.sizeToFit()
}
//实现搜索控制器委托协议
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
self.updateSearchResults(for: self.searchController)
}
//实现UISearchResultsUpdating 协议方法
func updateSearchResults(for searchController: UISearchController) {
self.filterContentForSearchText(searchText: searchController.searchBar.text! as NSString, scope: searchController.searchBar.selectedScopeButtonIndex)
self.tableView.reloadData()
}
//重写数据源协议
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//改为过滤查询之后的数据
return self.filterData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//故事版实现时,复用单元格时,使用该方法
let cell=tableView.dequeueReusableCell(withIdentifier: "cellIndentifier", for: indexPath)
let row=indexPath.row
let rowDic=self.filterData[row] as! NSDictionary
let imagePath=String.init(format: "%@.png", (rowDic.value(forKey: "image") as? String)!)
cell.imageView?.image=UIImage.init(named: imagePath)
cell.textLabel?.text=rowDic.value(forKey: "name") as? String
cell.detailTextLabel?.text=Date.init().description
//指定扩展视图的样式
cell.accessoryType = .disclosureIndicator
return cell
}
//过滤方法
func filterContentForSearchText(searchText: NSString,scope: Int) {
if(searchText.length==0){
self.filterData=NSMutableArray.init(array: self.data)
return
}
var tempArray:NSArray!
var scopePredicate:NSPredicate!
switch scope {
case 0:
//SELF.name 字典对象的健,或者实体对象的属性
scopePredicate=NSPredicate.init(format: "SELF.name contains[c] %@", searchText)
tempArray=self.filterData.filtered(using: scopePredicate) as NSArray
self.filterData=NSMutableArray.init(array: tempArray)
break
case 1:
scopePredicate=NSPredicate.init(format: "SELF.image contains[c] %@", searchText)
tempArray=self.filterData.filtered(using: scopePredicate) as NSArray
self.filterData=NSMutableArray.init(array: tempArray)
break
default:
self.filterData=NSMutableArray.init(array: self.data)
break
}
}
}
五、分节表视图
前面我们学习的都是只有一节的特殊的分节表视图,接下来我们看看分节,分组表视图
一般分节的话,可能会添加索引:
索引标题不能与显示的节标题一样,否则没有意义了
索引标题应具有代表性,能代表一个数据集合
如果采用索引列表视图,一般情况下不再使用扩展视图了
我不再用故事版演示了,比较简单,直接代码展示
//
// ViewController.swift
// P6UITableViewSelectionsCode
//
// Created by LF on 2017/4/8.
// Copyright © 2017年 yinwei. All rights reserved.
//
import UIKit
class ViewController: UITableViewController {
var dataDic:NSDictionary!
var dataGroups:NSArray!
var sectionTitles=[String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let plistPath=Bundle.main.path(forResource: "team_dictionary", ofType: "plist")
self.dataDic=NSDictionary.init(contentsOfFile: plistPath!)
//对分组进行排序
self.dataGroups=(dataDic.allKeys as NSArray).sortedArray(using: #selector(NSNumber.compare(_:))) as NSArray
//声明字符串数组 对索引添加数据
for groupName in self.dataGroups {
let name=groupName as! String
//截取开头的一个字符
let index=name.index(name.startIndex, offsetBy: 1)
let title=(name.substring(to:index)) as String
//截取结尾的字符怎么弄呢?举个例子:
/* let index=name.index(name.endIndex, offsetBy: -1)
let title=name.substring(from: index)*/
sectionTitles.append(title)
}
//设置表视图样式 为分组样式
self.tableView=UITableView.init(frame: self.view.frame, style: UITableViewStyle.grouped)
}
//返回每个节的行数
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let key=self.dataGroups[section] as! String
let sectionArray=(self.dataDic.value(forKey: key)) as! NSArray
return sectionArray.count
}
//返回每个节中的每个单元格
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell!=tableView.dequeueReusableCell(withIdentifier: "CellIdentifier")
if(cell==nil){
cell=UITableViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: "CellIdentifier" )
}
//获取节数
let section:Int=indexPath.section
//获取行数
let row:Int=indexPath.row
let keyName = self.dataGroups[section] as! String
let itemData=((self.dataDic.value(forKey: keyName)) as! NSArray)[row] as! String
cell.textLabel?.text=itemData
return cell
}
//返回节数
override func numberOfSections(in tableView: UITableView) -> Int {
return self.dataGroups.count
}
//返回节头标题
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.dataGroups[section] as? String
}
// //设置索引序列
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sectionTitles
}
}
效果图:
六、静态表与界面布局
我们要实现如下界面
我们通过效果图可以看出这十个表视图,并且是分组表视图,在ios 5之前这样的界面必须通过代码来实现,但是幸运的是我们闲在有故事版了,通过表视图的静态表来实现特别简单,来试一下吧
删除原本的控制器,添加表视图控制器没啥可说的,之前做国好多次了,看一些具体细节
对Table View设置为静态表,style为分组表,三个小节
第一个Table View Cell 为2行
最后打开辅助视图编辑器,绑定到控制器就OK了
//
// ViewController.swift
// P6UITableViewStatic
//
// Created by LF on 2017/4/9.
// Copyright © 2017年 yinwei. All rights reserved.
//
import UIKit
class ViewStaticController: UITableViewController {
@IBOutlet weak var password: UITextField!
@IBOutlet weak var userName: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func login(_ sender: Any) {
if(self.userName.text=="LF"&&self.password.text=="123456"){
NSLog("登陆成功!")
self.userName.resignFirstResponder()
self.password.resignFirstResponder()
}
}
}
七、插入和删除单元格
先看效果图
这里是导航栏和表视图结合的方式来实现的,我们看看如何使用故事版文件实现先
删除故事版中原本的控制器
添加
初始控制器为导航栏控制器
虽然初始控制器为导航栏控制器,但是我们的控制器文件还是表视图控制器
别忘了给单元格设置复用标识
这里特别的是我们添加了一个UITextField控件到我们的视图控制器中,
打开辅助视图编辑器,绑定到我们的控制器文件中去
最后看我们的控制器文件具体代码实现
//
// ViewController.swift
// P6UITableViewDeleteAndAdd
//
// Created by LF on 2017/4/9.
// Copyright © 2017年 yinwei. All rights reserved.
//
import UIKit
class ViewTableController: UITableViewController,UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
var datas:NSMutableArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//设置导航栏右边按钮 为编辑按钮
self.navigationItem.rightBarButtonItem=self.editButtonItem
//设置导航栏标题
self.navigationItem.title="单元格插入和删除"
//设置单元格文本框
self.textField.isHidden=true
self.textField.delegate=self
//模拟初始化数据
self.datas=NSMutableArray.init(array: ["黑龙江","吉林","辽宁"])
}
//UIViewController生命周期方法,用于响应视图编辑状态变化
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
self.tableView.setEditing(editing, animated: animated)
if editing{
self.textField.isHidden=false
}else{
self.textField.isHidden=true
}
}
//返回这个节中单元格数量
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//返回的是数据个数 加上 最后的操作单元格
return self.datas.count+1
}
//单元格数据绑定
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellindentifier = "CellIdentifier"
//判断是否是最后一个单元格 用来判断是否显示
let b_addCell:Bool=(self.datas.count == indexPath.row)
let cell:UITableViewCell!=tableView.dequeueReusableCell(withIdentifier: cellindentifier, for: indexPath)
if(!b_addCell){
cell.accessoryType = .disclosureIndicator
cell.textLabel?.text=self.datas[indexPath.row] as? String
}else{
//把我们添加到表视图中的UITextField 添加到单元格中去,故事版中可能添加一个控件的行为比较难理解,后面看代码实现就明白了
self.textField.frame=CGRect(x: 40,y: 0,width: 300,height: cell.frame.size.height)
self.textField.borderStyle = .none
self.textField.placeholder = "Add..."
self.textField.text = ""
cell.addSubview(self.textField)
}
return cell
}
//编辑插入和删除单元格的图标样式
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
if(indexPath.row == self.datas.count){
return UITableViewCellEditingStyle.insert
}
return UITableViewCellEditingStyle.delete
}
//插入和删除单元格的操作
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
//单元格的索引集合
let indexPaths:[IndexPath]=NSArray.init(array: [indexPath]) as! [IndexPath]
if(editingStyle == .delete){
self.datas.removeObject(at: indexPath.row)
self.tableView.deleteRows(at: indexPaths, with: UITableViewRowAnimation.fade)
}else{
self.datas.insert(self.textField.text ?? "", at: self.datas.count)
self.tableView.insertRows(at: indexPaths, with: UITableViewRowAnimation.fade)
}
self.tableView.reloadData()
}
//设置是否最后一行高亮显示
override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
if(indexPath.row==self.datas.count){
return false
}else{
return true
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
这样就结束了,可能这样我觉得比较难以理解,我们再完全使用代码写一遍,看着代码结构就会比较好理解了
首先看app代理文件
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.window=UIWindow.init(frame: UIScreen.main.bounds)
//根视图控制器为UINavigationController
self.window?.rootViewController=UINavigationController.init(rootViewController: ViewController())
self.window?.backgroundColor=UIColor.white
self.window?.makeKeyAndVisible()
return true
}
......
控制器文件
//
// ViewController.swift
// P6UITableViewDeleteAndAddCode
//
// Created by LF on 2017/4/9.
// Copyright © 2017年 yinwei. All rights reserved.
//
import UIKit
class ViewController: UITableViewController,UITextFieldDelegate{
var textField:UITextField!
var datas:NSMutableArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//设置导航栏右边按钮 为编辑按钮
self.navigationItem.rightBarButtonItem=self.editButtonItem
//设置导航栏标题
self.navigationItem.title="单元格插入和删除"
//模拟初始数据
self.datas=NSMutableArray.init(array: ["黑龙江","吉林","辽宁"])
//初始UITextField 控件 位置并没有初始化 只是知道有这么个控件
self.textField=UITextField.init()
self.textField.isHidden=true
self.textField.delegate=self
}
//UIViewController生命周期方法,用于响应视图编辑状态变化
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
self.tableView.setEditing(editing, animated: animated)
if editing{
self.textField.isHidden=false
}else{
self.textField.isHidden=true
}
}
//返回这个节中单元格数量
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//返回的是数据个数 加上 最后的操作单元格
return self.datas.count+1
}
//单元格数据绑定
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellindentifier = "CellIdentifier"
//判断是否是最后一个单元格 用来判断是否显示
let b_addCell:Bool=(self.datas.count == indexPath.row)
var cell:UITableViewCell!=tableView.dequeueReusableCell(withIdentifier: cellindentifier)
if(cell==nil){
cell=UITableViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: cellindentifier)
}
if(!b_addCell){
cell.accessoryType = .disclosureIndicator
cell.textLabel?.text=self.datas[indexPath.row] as? String
}else{
//把我们添加到表视图中的UITextField 添加到单元格中去
self.textField.frame=CGRect(x: 40,y: 0,width: 300,height: cell.frame.size.height)
self.textField.borderStyle = .none
self.textField.placeholder = "Add..."
self.textField.text = ""
cell.addSubview(self.textField)
}
return cell
}
//编辑插入和删除单元格的图标样式
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
if(indexPath.row == self.datas.count){
return UITableViewCellEditingStyle.insert
}
return UITableViewCellEditingStyle.delete
}
//插入和删除单元格的操作
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
//单元格的索引集合
let indexPaths:[IndexPath]=NSArray.init(array: [indexPath]) as! [IndexPath]
if(editingStyle == .delete){
self.datas.removeObject(at: indexPath.row)
self.tableView.deleteRows(at: indexPaths, with: UITableViewRowAnimation.fade)
}else{
self.datas.insert(self.textField.text ?? "", at: self.datas.count)
self.tableView.insertRows(at: indexPaths, with: UITableViewRowAnimation.fade)
}
self.tableView.reloadData()
}
//设置是否最后一行高亮显示
override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
if(indexPath.row==self.datas.count){
return false
}else{
return true
}
}
}
八、移动单元格
根据上一节的基础我们很容易就可以实现,具体直接看代码吧
效果图
主要代码:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.window=UIWindow.init(frame: UIScreen.main.bounds)
self.window?.rootViewController=UINavigationController.init(rootViewController: ViewController())
self.window?.backgroundColor=UIColor.white
self.window?.makeKeyAndVisible()
return true
}
....
控制器
//
// ViewController.swift
// P6UITableViewMoveCode
//
// Created by LF on 2017/4/9.
// Copyright © 2017年 yinwei. All rights reserved.
//
import UIKit
class ViewController: UITableViewController {
var datas:NSMutableArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//初始化导航控制器按钮和标题
self.navigationItem.rightBarButtonItem=self.editButtonItem
self.navigationController?.title="可以移动的单元格"
//初始化模拟数据
self.datas=NSMutableArray.init(array: ["黑龙江","吉林","辽宁"])
}
//设置编辑状态时 返回的单元格的开头编辑按钮是啥都没有
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
//设置单元格是否可以移动
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
//拖动单元格时 对数据重新排序
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
//取出想要移动的数据
let soureData=self.datas[sourceIndexPath.row] as! String
self.datas.removeObject(at: sourceIndexPath.row)
self.datas.insert(soureData, at: destinationIndexPath.row)
}
//其他的一些协议
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.datas.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier="CellIdentifier"
var cell:UITableViewCell!=tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
if(cell==nil){
cell=UITableViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: cellIdentifier)
}
let row=indexPath.row
cell.textLabel?.text=self.datas[row] as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
九、表视图UI设计模式
这里面就是介绍分页加载,和下拉刷新的,分页加载先不说,我们看下拉刷新,ios6之后ios直接支持下拉刷新
我们再上一节的代码的基础上更改,最后的效果图如下
这里需要说的时,只有根视图控制器为表视图控制器时,才可以使用,而且必须通过代码实现
直接上代码
//
// ViewController.swift
// P6UITableViewMoveCode
//
// Created by LF on 2017/4/9.
// Copyright © 2017年 yinwei. All rights reserved.
//
import UIKit
class ViewController: UITableViewController {
var datas:NSMutableArray!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//初始化导航控制器按钮和标题
self.navigationItem.rightBarButtonItem=self.editButtonItem
self.navigationController?.title="可以移动的单元格"
//初始化模拟数据
self.datas=NSMutableArray.init(array: ["黑龙江","吉林","辽宁"])
//设置下拉刷新 下拉刷新 通过 UIRefreshControl()实现
let rc=UIRefreshControl()
rc.attributedTitle=NSAttributedString.init(string: "下拉刷新")
//设置下拉刷新时 响应的函数
rc.addTarget(self, action: #selector(ViewController.refreshDatas), for: UIControlEvents.valueChanged)
self.refreshControl=rc
}
//设置下拉刷新时操作的函数
func refreshDatas() {
if(self.refreshControl?.isRefreshing==true){
self.refreshControl?.attributedTitle=NSAttributedString.init(string: "加载中...")
//设置个定时器模拟请求数据刷新的样子
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(ViewController.endRefresh), userInfo: nil, repeats: false)
}
}
func endRefresh() {
//对移动的数据还原
self.datas=NSMutableArray.init(array: ["黑龙江","吉林","辽宁"])
self.refreshControl?.endRefreshing()
self.refreshControl?.attributedTitle=NSAttributedString.init(string: "下拉刷新")
self.tableView.reloadData()
}
//设置编辑状态时 返回的单元格的开头编辑按钮是啥都没有
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
//设置单元格是否可以移动
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
//拖动单元格时 对数据重新排序
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
//取出想要移动的数据
let soureData=self.datas[sourceIndexPath.row] as! String
self.datas.removeObject(at: sourceIndexPath.row)
self.datas.insert(soureData, at: destinationIndexPath.row)
}
//其他的一些协议
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.datas.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier="CellIdentifier"
var cell:UITableViewCell!=tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
if(cell==nil){
cell=UITableViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: cellIdentifier)
}
let row=indexPath.row
cell.textLabel?.text=self.datas[row] as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
我们的UITableView的学习暂时告一段落,这一节主要学习一些简单的应用,以后我们做项目时在深入了解