ios 10之高级控件UITableView(swift 3.0 )

时间:2022-06-03 17:10:36

这篇会很长,因为UITableView很重要,几乎处处会见到它的影子。
一、UITableView的简单介绍
1、表视图的组成
ios 10之高级控件UITableView(swift 3.0 )

表头 表脚 单元格 节 ,当然节 也分为节头 节脚 可以显示节的信息或者声明

2、表视图的相关类
ios 10之高级控件UITableView(swift 3.0 )

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,我们拖进去一个
ios 10之高级控件UITableView(swift 3.0 )

选中ios 10之高级控件UITableView(swift 3.0 )
就可以表明该视图是初始视图控制器
ios 10之高级控件UITableView(swift 3.0 )

更改ios 10之高级控件UITableView(swift 3.0 )

控制器是指向我们自己的控制器,这个控制器是继承UITableViewController的,这里我修改的时候有时候无法修改,不知道咋回事,必须给ViewController改改名字才能在这里改,不知道啥情况。。。

然后给单元格加上复用标签

ios 10之高级控件UITableView(swift 3.0 )

这就好了,接下来看控制器代码

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

}


}

ios 10之高级控件UITableView(swift 3.0 )

纯代码实现:不使用 故事版文件代码 如下:

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.
}


}

三、自定义单元格
单元格虽然有几个自带的样式,但是有时候肯定无法满足我们的需求,这个时候就需要自己定义了,首先看故事版自定义如何实现:
很简单直接往单元格里面拖拽自己想定义的控件即可,
ios 10之高级控件UITableView(swift 3.0 )

然后创建自定义单元格继承UITableCell
ios 10之高级控件UITableView(swift 3.0 )

然后修改故事版中单元格属于自定义单元格所属的类
ios 10之高级控件UITableView(swift 3.0 )

然后打开辅助视图,让故事版单元格中的控件和自定义单元格类互相绑定即可,其他代码里面有注释

单元格类

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来实现表视图的,用搜索栏的控制器来实现比较方便简单,当然我们也可以直接在故事版文件中拖拽一个,然后设置它的属性
ios 10之高级控件UITableView(swift 3.0 )

但是不建议这么做,我们使用控制器来实现
最后的效果图:
ios 10之高级控件UITableView(swift 3.0 )

ios 10之高级控件UITableView(swift 3.0 )

直接看控制器代码:

//
// 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 10之高级控件UITableView(swift 3.0 )

六、静态表与界面布局
我们要实现如下界面
ios 10之高级控件UITableView(swift 3.0 )

我们通过效果图可以看出这十个表视图,并且是分组表视图,在ios 5之前这样的界面必须通过代码来实现,但是幸运的是我们闲在有故事版了,通过表视图的静态表来实现特别简单,来试一下吧
删除原本的控制器,添加表视图控制器没啥可说的,之前做国好多次了,看一些具体细节
ios 10之高级控件UITableView(swift 3.0 )

对Table View设置为静态表,style为分组表,三个小节
ios 10之高级控件UITableView(swift 3.0 )

第一个Table View Cell 为2行
ios 10之高级控件UITableView(swift 3.0 )

最后打开辅助视图编辑器,绑定到控制器就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()

}

}
}

七、插入和删除单元格
先看效果图
ios 10之高级控件UITableView(swift 3.0 )
ios 10之高级控件UITableView(swift 3.0 )

ios 10之高级控件UITableView(swift 3.0 )

ios 10之高级控件UITableView(swift 3.0 )

ios 10之高级控件UITableView(swift 3.0 )

这里是导航栏和表视图结合的方式来实现的,我们看看如何使用故事版文件实现先
删除故事版中原本的控制器
添加
ios 10之高级控件UITableView(swift 3.0 )

初始控制器为导航栏控制器
ios 10之高级控件UITableView(swift 3.0 )

ios 10之高级控件UITableView(swift 3.0 )

ios 10之高级控件UITableView(swift 3.0 )

虽然初始控制器为导航栏控制器,但是我们的控制器文件还是表视图控制器
ios 10之高级控件UITableView(swift 3.0 )

别忘了给单元格设置复用标识
ios 10之高级控件UITableView(swift 3.0 )

这里特别的是我们添加了一个UITextField控件到我们的视图控制器中,
ios 10之高级控件UITableView(swift 3.0 )

打开辅助视图编辑器,绑定到我们的控制器文件中去

最后看我们的控制器文件具体代码实现

//
// 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
}
}


}

八、移动单元格

根据上一节的基础我们很容易就可以实现,具体直接看代码吧

效果图
ios 10之高级控件UITableView(swift 3.0 )

ios 10之高级控件UITableView(swift 3.0 )

主要代码:

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直接支持下拉刷新

我们再上一节的代码的基础上更改,最后的效果图如下

ios 10之高级控件UITableView(swift 3.0 )
这里需要说的时,只有根视图控制器为表视图控制器时,才可以使用,而且必须通过代码实现
直接上代码

//
// 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的学习暂时告一段落,这一节主要学习一些简单的应用,以后我们做项目时在深入了解