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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值