Swift创建一个选择题库界面(解决TableViewCell中
Swift创建一个选择题库界面(解决TableViewCell中Button的selected状态混乱和手势事件被截拦问题)-1
Swift创建一个选择题库界面(解决TableViewCell中Button的selected状态混乱和手势事件被截拦问题)-2
Swift创建一个选择题库界面(解决TableViewCell中Button的selected状态混乱和手势事件被截拦问题)-3
手势事件被截拦问题
通过给每个optionsBtn设置tag可以解决在Cell中不响应button的问题,现在如果要在点击optionsLabel的时候也响应button的点击事件,怎么实现呢。
Cell中View的层级关系如下:
contentView -> backView -> (optionsBtn,optionsLabel,...)```
给optionLabel添加手势?答案是否定的,添加的手势只能是contentView的下一层,即backView(我试过了,具体为什么,我也不清楚)。思路如下:
1.给backView添加点击手势
2.通过gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool
方法获取touch,并根据touch.gestureRecognizers来判断是否截拦手势,return true为截拦,return false为不截拦。
如果你不添加手势,touch.gestureRecognizers就为nil,添加了一个UITapGestureRecognizer手势,
touch.gestureRecognizers=[UITapGestureRecognizer].
3.在响应手势的action中,通过手势在的pointX在哪个optionsLabel里来判断点击了哪一个optionsLabel,对应的就是哪一个button了```
代码如下:
//XXWDCell.swift
override func drawRect(rect: CGRect) {
backView.layer.cornerRadius = 10
backView.layer.masksToBounds = true
//给backView添加手势
let tag = UITapGestureRecognizer(target: self, action: #selector(XXWDCell.gestureRecognizerAction(_:)))
self.backView.addGestureRecognizer(tag)
}
func gestureRecognizerAction(tag:UIGestureRecognizer) {
//通过touch在backView中的位置,来判断是在哪个optionLabel中
let pointX = tag.locationInView(self.backView)
for i in 0..<self.optionsLabel.count {
if self.optionsLabel[i].frame.contains(pointX) {
let button = self.optionsBtn[i]//通过i获取相应的button
self.selectAnswerAction(button)//调用button点击事件,相当于点击了button
}
}
}
override func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.gestureRecognizers == nil {
return true
}
for tag in touch.gestureRecognizers! {
if tag.isKindOfClass(UITapGestureRecognizer) {
return false
}
}
return true
}
这样在点击optionsLabel的时候,optionsBtn也会变化。
获取答案
1.selectAnswerAction点击事件,获取答案,并通过block的方式传给viewcontroller,为元组(Bool,String),bool为答案是否正确,string为"ABC"这样的字符串,之所以传bool就是要统计有多少个正确答案
2.updateBtnsSelectedState单选时只能选中一个:遍历optionsBtn,如果非当前选中的button,则btn.selected = false
3.answer(),简单一点就是如果是单选,只保留当前选中的,如果是多选则删除重复的。最开始就是要把第1、2、3、4个button转换成A、B、C、D,我的算法就是,你每次点击了,我就判断一下有哪些选中了,并把它add到selectedArray中,把非选中的删除。举例说明,多选,我可能先点击了D,然后点击了C,然后又点击了D要取消,然后点击了A想选A。第一次点击selectedArray = ["D"] ,第二次 ["D","C"],第三次["C"],第四次["C","A"],然后排序["A","C"],转换成string 答案AC。
//XXWDCell.swift
let answerList = ["A","B","C","D","E","F","G","H","I","J"]
typealias SelectType = (Bool,String)-> ()
var selecteAnswerBlock:SelectType?
var selectedArray:NSMutableArray = NSMutableArray()
var selecteStateArray:NSMutableArray = NSMutableArray()
@IBAction func selectAnswerAction(sender: UIButton) {
if self.selecteAnswerBlock != nil {
sender.selected = !sender.selected
updateBtnsSelectedState(sender)//单选时,只能选中一个
let answer = answer(sender)
selecteAnswerBlock!((answer.0,answer.1))//不要写answer(sender).0,answer(sender).1这样会执行两次answer(sender)
}
}
func updateBtnsSelectedState(sender:UIButton) {
if model!.type == "单选" {
let tag = 100 + model!.index.integerValue * 4
let btns = [self.viewWithTag(tag),self.viewWithTag(tag + 1),self.viewWithTag(tag + 2),self.viewWithTag(tag + 3)]
for view in btns {
let btn = view as! UIButton
if sender != btn {
btn.selected = false
}
}
}
}
func answer(sender:UIButton) -> (Bool,String){
var selectedAnswer:String = ""
if sender.selected {
if model!.type == "单选" {
selectedArray.removeAllObjects()
selectedArray = [self.answerList[sender.tag - 100 - model!.index.integerValue * 4]]
}
if model!.type == "多选" {
selectedArray.addObject(self.answerList[sender.tag - 1000 - model!.index.integerValue * 4])
}
}else {
//非选中之后删除相应的选项
if model!.type == "单选" {
selectedArray.removeAllObjects()
}
if model!.type == "多选" {
for char in selectedArray {
if char as! String == self.answerList[sender.tag - 1000 - model!.index.integerValue * 4] {
selectedArray.removeObject(char)
}
}
}
}
//排序
let sortedArray = selectedArray.sort { (s1, s2) -> Bool in
return (s1 as! String) < (s2 as! String)
}
//转换成String
for c in sortedArray {
if model?.type == "单选" {
selectedAnswer = c as! String
} else {
selectedAnswer = selectedAnswer + (c as! String)
}
}
//防止发生崩溃
if sortedArray.count == 0 {
selectedAnswer = ""
}
//防止单选后,做多选题时,会保留单选答案
if model!.type == "单选" {
selectedArray.removeAllObjects()
}
return (selectedAnswer == model?.answer,selectedAnswer)
}
如何解决混乱的问题
混乱就是第一个cell中选中了A选项,你会发现在后面的第4、8个cell中均选中了A选项,但是第4、8个cell并没有响应button点击事件。没有响应button点击时间是好的,现在只要解决在其他cell中也出现选中的情况。
解决的办法比较原始,那就是:在tableview willdisplay方法中,先把所有的optionsBtn的selected=false,根据获得的答案来设置optionsBtn的状态,比如说,答案是ABC,如果答案中有A,就设置optionsBtn[0].selected = true以此类推。
singleChoiceArray,multipleChoiceArray分别为单选和多选的题目数组
//XXWDController.swift
var scores:Int = 0//答对题数
lazy var singleChoiceResult:NSMutableArray = {//存储单选是否正确bool
let aArray = NSMutableArray()
for i in 0..<self.singleChoiceArray.count {
aArray.addObject(false)
}
return aArray
}()
lazy var multipleChoiceResult:NSMutableArray = {//存储多选是否正确bool
let aArray = NSMutableArray()
for i in 0..<self.multipleChoiceArray.count {
aArray.addObject(false)
}
return aArray
}()
lazy var selectedResult:NSMutableArray = {//用来保存答案string,来判断btn的选中状态
let aArray = NSMutableArray()
for i in 0..<self.multipleChoiceArray.count + self.singleChoiceArray.count {
aArray.addObject("H")//"H"其实就是给一个ABCD之外,不可能有的选项,来初始化selectedResult
}
return aArray
}()
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
//防止复用时,发生混乱,比如选中1中的A在4行中的A也在选中状态,通过重置和复置来还原
for i in 0..<4 {
xxwdcell.optionsBtn[i].selected = false
}
var idx = 0
if indexPath.section == 0 {
idx = indexPath.row
}
if indexPath.section == 1 {
idx = indexPath.row + self.singleChoiceArray.count
}
//通过判断所在行的答案是否包含某个选项,来确定该optionsBtn是否被选中
let str = self.selectedResult[idx] as! String
if str.containsString("A") {
xxwdcell.optionsBtn[0].selected = true
}
if str.containsString("B") {
xxwdcell.optionsBtn[1].selected = true
}
if str.containsString("C") {
xxwdcell.optionsBtn[2].selected = true
}
if str.containsString("D") {
xxwdcell.optionsBtn[3].selected = true
}
//按钮回调事件
xxwdcell.selecteAnswerBlock = {[unowned self]
result,answ in
if indexPath.section == 0{
//将结果分别存储,result为Bool,answ为答案String
self.singleChoiceResult.replaceObjectAtIndex(indexPath.row, withObject: result)
self.selectedResult.replaceObjectAtIndex(indexPath.row, withObject: answ)
}
if indexPath.section == 1{
self.multipleChoiceResult.replaceObjectAtIndex(indexPath.row, withObject: result)
self.selectedResult.replaceObjectAtIndex(indexPath.row + self.singleChoiceArray.count, withObject: answ)
}
}
if indexPath.section == 0 {
//设置选择按钮的tag,防止复用时发生混乱
for i in 0..<4 {
xxwdcell.optionsBtn[i].tag = 100 + indexPath.row * 4 + i
}
}
if indexPath.section == 1 {
//设置选择按钮的tag,防止复用时发生混乱
for i in 0..<4 {
xxwdcell.optionsBtn[i].tag = 1000 + indexPath.row * 4 + i
}
}
xxwdcell.model = exercise
}