swift实现表格视图单元格单选(2)-kb88凯时官网登录

来自:网络
时间:2023-07-25
阅读:

本文实例为大家分享了swift实现表格视图单元格单选的具体代码,供大家参考,具体内容如下

效果

swift实现表格视图单元格单选(2)

前言

前段时间写了一篇博客: ,实现起来并不复杂,简单易懂。在实际开发中,可能会涉及到更为复杂的操作,比如多个section 下的单选,如上面展示的效果,当我们有这样的需求的时候,该如何实现呢?因为,在上篇文章中我所用的控件都是单元格自带的imageview以及textlabel,本文我将主要分享自定义选择按钮以及在多个section下实现单选的方法。

准备

界面搭建与数据显示

swift实现表格视图单元格单选(2)

这样的界面相信对大家而言,并不难,这里我不再做详细的讲解,值得一提的是数据源的创建,每一组的头部标题,我用一个数组questions存储,类型为:[string]?,由于每一组中,单元格内容不一致,因此建议用字典存储。如下所示:

var questions: [string]?
var answers:   [string:[string]]?

如果我用字典来存储数据,那字典的键我应该如何赋值呢?其实很简单,我们只需将section的值作为key 就ok了,这样做的好处在于,我可以根据用户点击的 section来处理对应的数据,我们知道,表格视图的section 从 0 开始,因此字典赋值可以像下面提供的代码一样赋值,但要注意,answers的值需与questions里面的问题一致,才能满足实际的需求。

self.questions = ["您的性别是:",
                  "您意向工作地点是:",
                  "您是否参加公司内部培训:"]
self.answers = ["0":["男", "女"],
                "1":["成都", "上海", "北京", "深圳"],
                "2":["参加", "不参加","不确定"]]

接下来需要做的事情就是自定义单元格(uitableviewcell)了,比较简单,直接上代码,代码中涉及到的图片素材可到阿里矢量图中下载:

import uikit
class customtableviewcell: uitableviewcell {
    var choicebtn: uibutton?
    var displaylab: uilabel?
    override init(style: uitableviewcellstyle, reuseidentifier: string?) {
        super.init(style: style, reuseidentifier: reuseidentifier)
        self.initializeuserinterface()
    }
    required init?(coder adecoder: nscoder) {
        fatalerror("init(coder:) has not been implemented")
    }
    // mark:initialize methods
    func initializeuserinterface() {
        self.choicebtn = {
            let choicebtn = uibutton(type: uibuttontype.custom)
            choicebtn.bounds = cgrectmake(0, 0, 30, 30)
            choicebtn.center = cgpointmake(20, 22)
            choicebtn.setbackgroundimage(uiimage(named: "iconfont-select.png"), forstate: uicontrolstate.normal)
            choicebtn.setbackgroundimage(uiimage(named: "iconfont-selected.png"), forstate: uicontrolstate.selected)
            choicebtn.addtarget(self, action: selector("respondstobutton:"), forcontrolevents: uicontrolevents.touchupinside)
            return choicebtn
            }()
        self.contentview.addsubview(self.choicebtn!)
        self.displaylab = {
            let displaylab = uilabel()
            displaylab.bounds = cgrectmake(0, 0, 100, 30)
            displaylab.center = cgpointmake(cgrectgetmaxx(self.choicebtn!.frame)   60, cgrectgetmidy(self.choicebtn!.frame))
            displaylab.textalignment = nstextalignment.left
            return displaylab
            }()
        self.contentview.addsubview(self.displaylab!)
    }
    // mark:events
    func respondstobutton(sender: uibutton) {
    }
}

表格视图数据源与代理的实现,如下所示:

// mark:uitableviewdatasource && uitableviewdelegate
func numberofsectionsintableview(tableview: uitableview) -> int {
    // 直接返回 answers 键值对个数即可,也可返回 questions 个数;
    return (self.answers!.count)
}
func tableview(tableview: uitableview, numberofrowsinsection section: int) -> int {
    // 根据 section 获取对应的 key
    let key = "\(section)"
    // 根据 key 获取对应的数据(数组)
    let answers = self.answers![key]
    // 直接返回数据条数,就是需要的行数
    return answers!.count
}
func tableview(tableview: uitableview, cellforrowatindexpath indexpath: nsindexpath) -> uitableviewcell {
    var cell: customtableviewcell? = tableview.dequeuereusablecellwithidentifier("cell") as? customtableviewcell
    if cell == nil {
        cell = customtableviewcell(style: uitableviewcellstyle.default, reuseidentifier: "cell")
    }
    let key = "\(indexpath.section)"
    let answers = self.answers![key]
    cell!.selectionstyle = uitableviewcellselectionstyle.none
    return cell!
}
func tableview(tableview: uitableview, heightforheaderinsection section: int) -> cgfloat {
    return 40
}
func tableview(tableview: uitableview, titleforheaderinsection section: int) -> string? {
    return self.questions![section]
}

实现

技术点:在这里我主要会用到闭包回调,在自定义的单元格中,用户点击按钮触发方法时,闭包函数会被调用,并将用户点击的单元格的indexpath进行传递,然后根据indexpath进行处理,具体的实现方式,下面会慢慢讲到,闭包类似于objective-c中的block,有兴趣的朋友可深入了解swift中的闭包使用。

首先,我们需要在customtableviewcell.swift文件中,声明一个闭包类型:

typealias indexpathclosure = (indexpath: nsindexpath) ->void

其次,声明一个闭包属性:

var indexpathclosure: indexpathclosure?

现在,要做的事情就是声明一个闭包函数了,闭包函数主要用于在viewcontroller.swift文件中调用并且将需要传递的数据传递到viewcontroller.swift文件中。

func getindexwithclosure(closure: indexpathclosure?) {
        self.indexpathclosure = closure
    }

闭包函数已经有了,那么何时调用闭包函数呢?当用户点击单元格的时候,闭包函数会被调用,因此,我们只需要到选择按钮触发方法中去处理逻辑就好了,在触发方法中,我们需要将单元格的indexpath属性传递出去,但是,uitableviewcell并无indexpath属性,那应该怎么办呢?我们可以为它创建一个indexpath属性,在配置表格视图协议方法cellforrowatindexpath:时,我们赋值单元格的indexpath属性就ok了。

var indexpath: nsindexpath?
func respondstobutton(sender: uibutton) {
    sender.selected = true
    if self.indexpathclosure != nil {
        self.indexpathclosure!(indexpath: self.indexpath!)
    }
}

现在在customtableviewcell.swift文件里面的操作就差不多了,但是,还缺少一步,我还需要定制一个方法,用于设置按钮的状态:

func setchecked(checked: bool) {
    self.choicebtn?.selected = checked
}

到了这一步,我们要做的事情就是切换到viewcontroller.swift文件中,找到表格视图协议方法cellforrowatindexpath:,主要的逻辑就在这个方法中处理,首先我们需要做的事情就是赋值自定义单元格的indexpath属性:

cell?.indexpath = indexpath

其次,我需要在viewcontroller.swift文件中,声明一个selectedindexpath属性用于记录用户当前选中的单元格位置:

var selectedindexpath: nsindexpath?

接下来我会去做一个操作,判断协议方法参数indexpath.row,是否与selectedindexpath.row一致,如果一致,则设为选中,否则设为未选中,这里可用三目运算符:

self.selectedindexpath?.row == indexpath.row ? cell?.setchecked(true) : cell?.setchecked(false)

这里大家可能会有疑问,那就是为什么只判断row呢?不用判断section吗?当然不用,因为在刷新表格视图的时候我并没有调用reloaddata方法,而是指定刷新某一组(section)就可以了,如果全部刷新,则无法保留上一组用户选择的信息,这将不是我们所需要的。

接下来,将是最后一步,调用回调方法,该方法会在每一次用户点击单元格的时候调用,并且返回用户当前点击的单元格的indexpath,在这里,我们需要将返回的indexpath赋值给selectedindexpath属性。并且刷新指定section就ok了,代码如下:

cell!.getindexwithclosure { (indexpath) -> void in
    self.selectedindexpath = indexpath
    print("您选择的答案是:\(answers![indexpath.row])")
    tableview.reloadsections(nsindexset(index: self.selectedindexpath!.section), withrowanimation: uitableviewrowanimation.automatic)   
}

完整代码

可能大家还比较模糊,这里我将贴上完整的代码供大家参考

viewcontroller.swift文件

import uikit
class viewcontroller: uiviewcontroller, uitableviewdatasource, uitableviewdelegate{
    var tableview: uitableview?
    var questions: [string]?
    var answers: [string:[string]]?
    var selectedindexpath: nsindexpath?
    override func viewdidload() {
        super.viewdidload()
        self.initializedatasource()
        self.initializeuserinterface()
        // do any additional setup after loading the view, typically from a nib.
    }
    // mark:initialize methods
    func initializedatasource() {
        self.questions = ["您的性别是:", "您意向工作地点是:", "您是否参加公司内部培训:"]
        self.answers = ["0":["男", "女"],
                        "1":["成都", "上海", "北京", "深圳"],
                        "2":["参加","不参加","不确定"]]
    }
    func initializeuserinterface() {
        self.title = "多组单选"
        self.automaticallyadjustsscrollviewinsets = false
        // table view
        self.tableview = {
            let tableview = uitableview(frame: cgrectmake(0, 64, cgrectgetwidth(self.view.bounds), cgrectgetheight(self.view.bounds)), style: uitableviewstyle.grouped)
            tableview.datasource = self
            tableview.delegate = self
            return tableview
            }()
        self.view.addsubview(self.tableview!)
    }
    // mark:uitableviewdatasource && uitableviewdelegate
    func numberofsectionsintableview(tableview: uitableview) -> int {
        return (self.answers!.count)
    }
    func tableview(tableview: uitableview, numberofrowsinsection section: int) -> int {
        let key = "\(section)"
        let answers = self.answers![key]
        return answers!.count
    }
    func tableview(tableview: uitableview, cellforrowatindexpath indexpath: nsindexpath) -> uitableviewcell {
        var cell: customtableviewcell? = tableview.dequeuereusablecellwithidentifier("cell") as? customtableviewcell
        if cell == nil {
            cell = customtableviewcell(style: uitableviewcellstyle.default, reuseidentifier: "cell")
        }
        cell?.indexpath = indexpath
        let key = "\(indexpath.section)"
        let answers = self.answers![key]
        self.selectedindexpath?.row == indexpath.row ? cell?.setchecked(true) : cell?.setchecked(false)
        cell!.getindexwithclosure { (indexpath) -> void in
            self.selectedindexpath = indexpath
            print("您选择的答案是:\(answers![indexpath.row])")
            tableview.reloadsections(nsindexset(index: self.selectedindexpath!.section), withrowanimation: uitableviewrowanimation.automatic)
        }
        cell!.displaylab?.text = answers![indexpath.row]
        cell!.selectionstyle = uitableviewcellselectionstyle.none
        return cell!
    }
    func tableview(tableview: uitableview, heightforheaderinsection section: int) -> cgfloat {
        return 40
    }
    func tableview(tableview: uitableview, titleforheaderinsection section: int) -> string? {
        return self.questions![section]
    }
}

customtableviewcell.swift文件

import uikit
typealias indexpathclosure = (indexpath: nsindexpath) ->void
class customtableviewcell: uitableviewcell {
    var choicebtn: uibutton?
    var displaylab: uilabel?
    var indexpath: nsindexpath?
    var indexpathclosure: indexpathclosure?
    override init(style: uitableviewcellstyle, reuseidentifier: string?) {
        super.init(style: style, reuseidentifier: reuseidentifier)
        self.initializeuserinterface()
    }
    required init?(coder adecoder: nscoder) {
        fatalerror("init(coder:) has not been implemented")
    }
    // mark:initialize methods
    func initializeuserinterface() {
        self.choicebtn = {
            let choicebtn = uibutton(type: uibuttontype.custom)
            choicebtn.bounds = cgrectmake(0, 0, 30, 30)
            choicebtn.center = cgpointmake(20, 22)
            choicebtn.setbackgroundimage(uiimage(named: "iconfont-select"), forstate: uicontrolstate.normal)
            choicebtn.setbackgroundimage(uiimage(named: "iconfont-selected"), forstate: uicontrolstate.selected)
            choicebtn.addtarget(self, action: selector("respondstobutton:"), forcontrolevents: uicontrolevents.touchupinside)
            return choicebtn
            }()
        self.contentview.addsubview(self.choicebtn!)
        self.displaylab = {
            let displaylab = uilabel()
            displaylab.bounds = cgrectmake(0, 0, 100, 30)
            displaylab.center = cgpointmake(cgrectgetmaxx(self.choicebtn!.frame)   60, cgrectgetmidy(self.choicebtn!.frame))
            displaylab.textalignment = nstextalignment.left
            return displaylab
            }()
        self.contentview.addsubview(self.displaylab!)
    }
    // mark:events
    func respondstobutton(sender: uibutton) {
        sender.selected = true
        if self.indexpathclosure != nil {
            self.indexpathclosure!(indexpath: self.indexpath!)
        }
    }
    // mark:private
    func setchecked(checked: bool) {
        self.choicebtn?.selected = checked
    }
    func getindexwithclosure(closure: indexpathclosure?) {
        self.indexpathclosure = closure
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

返回顶部
顶部
网站地图