Swift實現(xiàn)表格視圖單元格單選(2)
本文實例為大家分享了Swift實現(xiàn)表格視圖單元格單選的具體代碼,供大家參考,具體內(nèi)容如下
效果
前言
前段時間寫了一篇博客: 表格視圖單元格單選(一),實現(xiàn)起來并不復(fù)雜,簡單易懂。在實際開發(fā)中,可能會涉及到更為復(fù)雜的操作,比如多個section
下的單選,如上面展示的效果,當(dāng)我們有這樣的需求的時候,該如何實現(xiàn)呢?因為,在上篇文章中我所用的控件都是單元格自帶的imageView
以及textLabel
,本文我將主要分享自定義選擇按鈕以及在多個section
下實現(xiàn)單選的方法。
準(zhǔn)備
界面搭建與數(shù)據(jù)顯示
這樣的界面相信對大家而言,并不難,這里我不再做詳細的講解,值得一提的是數(shù)據(jù)源的創(chuàng)建,每一組的頭部標(biāo)題,我用一個數(shù)組questions
存儲,類型為:[String]?
,由于每一組中,單元格內(nèi)容不一致,因此建議用字典存儲。如下所示:
var questions: [String]? var answers: ? [String:[String]]?
如果我用字典來存儲數(shù)據(jù),那字典的鍵我應(yīng)該如何賦值呢?其實很簡單,我們只需將section
的值作為key
就Ok了,這樣做的好處在于,我可以根據(jù)用戶點擊的 section
來處理對應(yīng)的數(shù)據(jù),我們知道,表格視圖的section
從 0 開始,因此字典賦值可以像下面提供的代碼一樣賦值,但要注意,answers
的值需與questions
里面的問題一致,才能滿足實際的需求。
self.questions = ["您的性別是:", ? ? ? ? ? ? ? ? ? "您意向工作地點是:", ? ? ? ? ? ? ? ? ? "您是否參加公司內(nèi)部培訓(xùn):"] 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) { ? ? } }
表格視圖數(shù)據(jù)源與代理的實現(xiàn),如下所示:
// MARK:UITableViewDataSource && UITableViewDelegate func numberOfSectionsInTableView(tableView: UITableView) -> Int { ? ? // 直接返回 answers 鍵值對個數(shù)即可,也可返回 questions 個數(shù); ? ? return (self.answers!.count) } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ? ? // 根據(jù) section 獲取對應(yīng)的 key ? ? let key = "\(section)" ? ? // 根據(jù) key 獲取對應(yīng)的數(shù)據(jù)(數(shù)組) ? ? let answers = self.answers![key] ? ? // 直接返回數(shù)據(jù)條數(shù),就是需要的行數(shù) ? ? 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] }
實現(xiàn)
技術(shù)點:在這里我主要會用到閉包回調(diào),在自定義的單元格中,用戶點擊按鈕觸發(fā)方法時,閉包函數(shù)會被調(diào)用,并將用戶點擊的單元格的indexPath
進行傳遞,然后根據(jù)indexPath
進行處理,具體的實現(xiàn)方式,下面會慢慢講到,閉包類似于Objective-C中的Block,有興趣的朋友可深入了解Swift中的閉包使用。
首先,我們需要在CustomTableViewCell.swift
文件中,聲明一個閉包類型:
typealias IndexPathClosure = (indexPath: NSIndexPath) ->Void
其次,聲明一個閉包屬性:
var indexPathClosure: IndexPathClosure?
現(xiàn)在,要做的事情就是聲明一個閉包函數(shù)了,閉包函數(shù)主要用于在ViewController.swift
文件中調(diào)用并且將需要傳遞的數(shù)據(jù)傳遞到ViewController.swift
文件中。
func getIndexWithClosure(closure: IndexPathClosure?) { ? ? ? ? self.indexPathClosure = closure ? ? }
閉包函數(shù)已經(jīng)有了,那么何時調(diào)用閉包函數(shù)呢?當(dāng)用戶點擊單元格的時候,閉包函數(shù)會被調(diào)用,因此,我們只需要到選擇按鈕觸發(fā)方法中去處理邏輯就好了,在觸發(fā)方法中,我們需要將單元格的indexPath屬性傳遞出去,但是,UITableViewCell
并無indexPath
屬性,那應(yīng)該怎么辦呢?我們可以為它創(chuàng)建一個indexPath
屬性,在配置表格視圖協(xié)議方法cellForRowAtIndexPath:
時,我們賦值單元格的indexPath
屬性就OK了。
var indexPath: NSIndexPath?
func respondsToButton(sender: UIButton) { ? ? sender.selected = true ? ? if self.indexPathClosure != nil { ? ? ? ? self.indexPathClosure!(indexPath: self.indexPath!) ? ? } }
現(xiàn)在在CustomTableViewCell.swift
文件里面的操作就差不多了,但是,還缺少一步,我還需要定制一個方法,用于設(shè)置按鈕的狀態(tài):
func setChecked(checked: Bool) { ? ? self.choiceBtn?.selected = checked }
到了這一步,我們要做的事情就是切換到ViewController.swift
文件中,找到表格視圖協(xié)議方法cellForRowAtIndexPath:
,主要的邏輯就在這個方法中處理,首先我們需要做的事情就是賦值自定義單元格的indexPath
屬性:
cell?.indexPath = indexPath
其次,我需要在ViewController.swift
文件中,聲明一個selectedIndexPath
屬性用于記錄用戶當(dāng)前選中的單元格位置:
var selectedIndexPath: NSIndexPath?
接下來我會去做一個操作,判斷協(xié)議方法參數(shù)indexPath.row
,是否與selectedIndexPath.row
一致,如果一致,則設(shè)為選中,否則設(shè)為未選中,這里可用三目運算符:
self.selectedIndexPath?.row == indexPath.row ? cell?.setChecked(true) : cell?.setChecked(false)
這里大家可能會有疑問,那就是為什么只判斷row
呢?不用判斷section
嗎?當(dāng)然不用,因為在刷新表格視圖的時候我并沒有調(diào)用reloadData
方法,而是指定刷新某一組(section
)就可以了,如果全部刷新,則無法保留上一組用戶選擇的信息,這將不是我們所需要的。
接下來,將是最后一步,調(diào)用回調(diào)方法,該方法會在每一次用戶點擊單元格的時候調(diào)用,并且返回用戶當(dāng)前點擊的單元格的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 = ["您的性別是:", "您意向工作地點是:", "您是否參加公司內(nèi)部培訓(xùn):"] ? ? ? ? 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 ? ? } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
RxSwift發(fā)送及訂閱 Subjects、Variables代碼示例
這篇文章主要介紹了RxSwift發(fā)送及訂閱 Subjects、Variables代碼示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-12-12Swift Access Control訪問控制與斷言詳細介紹
這篇文章主要介紹了Swift Access Control訪問控制與斷言,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09