Swift创建一个选择题库界面(解决TableViewCell中

作者: 9ad91f89b29e | 来源:发表于2016-08-03 00:51 被阅读436次

    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
        }
    
    

    相关文章

      网友评论

      本文标题:Swift创建一个选择题库界面(解决TableViewCell中

      本文链接:https://www.haomeiwen.com/subject/tnkqsttx.html