UIPageController實現(xiàn) 問卷臀蛛、試卷

最近寫了一個問卷、試卷類型的需求浊仆,題型包括單選、多選豫领、簡答,并且每道題包括是否必選

看到這個需求的時候第一想法就是 CollectionView 嵌套UITableView實現(xiàn)一個左右滑動等恐,嵌套上下滑動洲劣,這么一個結構(網(wǎng)上類似的需求也多是這么實現(xiàn)的课蔬,大同小異)。

單選與多選的問題二跋,參照tableView 單選及多選的簡單實現(xiàn)

但是實現(xiàn)過程中战惊,發(fā)現(xiàn)一下幾個問題不是很容易解決

  • 滑動效果不是很理想扎即,CollectionView的滑動,開了pageEnabled之后谚鄙,滑動超過一半才會滑動過去,而不到一半的時候會回彈闷营。

  • 更新頁碼的時候烤黍,發(fā)現(xiàn)CollectionView的代理方法不能很好的滿足需求,而放在scrollViewDidScroll方法里面去判斷是否超過一半的時候變動蚊荣,可以實現(xiàn)效果莫杈,但是變化也不是很理想

  • 由于是CollectionView,對每個cell的監(jiān)聽就比較少了筝闹,最終必選的問題,被放大了关顷,找不到一個系統(tǒng)的代理糊秆、方法可以合理的處理必選的問題

綜合這些問題-------決定試試UIPageViewController

因為比較少用這個议双,因此也添了一些坑就不表了,直接上代碼

/// 答題的主題位置
func makePageViewController() {
    //主體答題位置平痰,設置樣式為 pageCurl 汞舱,
    pageViewController =  UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: [UIPageViewControllerOptionSpineLocationKey: NSNumber(value:UIPageViewControllerSpineLocation.min.rawValue)])
    pageViewController.view.frame = CGRect(x: Q_A.Padding.left, y: Q_A.Padding.top, width: view.frame.width - 2 * Q_A.Padding.left, height: view.frame.height - Q_A.Padding.top - answerCardFrame.height - 44 - 64)
    pageViewController.delegate = self
    pageViewController.dataSource = self
    
    pageViewController.isDoubleSided = false //單面
    pageViewController.cancleSideTouch()  //自定義宗雇,取消了邊緣響應點擊事件
            
    // 根據(jù)數(shù)據(jù)個數(shù),設置controller的數(shù)組赔蒲,并設置數(shù)據(jù)源
    for i in 0..<questions.count {
        let current = QuestionViewController()
        current.view.frame = pageViewController.view.bounds
        current.dataSource = (questions[i], realAnswer[i])
        
        viewControllers.append(current)
    }
    
    pageViewController.setViewControllers([viewControllers.first!], direction: .forward, animated: true) { (bool) in
        print("設置完成")
        self.addChildViewController(self.pageViewController)
        self.view.addSubview(self.pageViewController.view)
        
        self.pageViewController.didMove(toParentViewController: self) //前面兩句已經(jīng)加了,這句是什么意思舞虱?
    }
}

這個里面欢际,UIPageViewController 的滑動類型分為2種砾嫉,pageCurlscroll 設置了一個參數(shù) *** UIPageViewControllerOptionSpineLocationKey,這個參數(shù)控制的是書脊的位置焕刮,設置這個和UI的表現(xiàn)形式有關系舶沿,當且僅當 spineLocationKey 為mid***的時候配并,界面就像一本打開的書一樣,且默認設置了正反頁顯示溉旋。

這里面還涉及到pageViewController的 頁面設置方法

   open func setViewControllers(_ viewControllers: [UIViewController]?, direction: UIPageViewControllerNavigationDirection, animated: Bool, completion: ((Bool) -> Swift.Void)? = nil) 

方法中需要傳一個 viewControllers: [UIViewController]?畸冲,這個地方,根據(jù)pageViewController的 transitionStyle 的不同有所區(qū)別算行,當且僅當 transitionStyle 為.pageCurl && spineLocationKey 為.mid時,需要傳2個苫耸,剩下的需要傳一個VC

   'NSInvalidArgumentException', reason: 'The number of provided view controllers (1) doesn't match the number required (2) for the requested spine location (UIPageViewControllerSpineLocationMid)'

如果出現(xiàn)這種錯誤,就說明你的VC的個數(shù)和transitionStyle沖突了褪子,

   'UIPageViewControllerSpineLocationMid' is specified, 'doubleSided' must be 'YES'.' 

這個錯誤就很明顯了~

然后我們來看UIPageViewControllerDataSource中的方法

func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
    //獲取即將顯示的頁面的后一頁,
    let index = viewControllers.index(of: viewController)!
    if index == viewControllers.count - 1 { //第一條
        return nil
    }
    return viewControllers[pageIndex]
}

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
    //獲取即將顯示的頁面的前一頁
    let index = viewControllers.index(of: viewController)!
    if index == 0 { //第一條
        return nil
    }
    return viewControllers[pageIndex]
}

這里踩過坑,試過通過pageIndex 直接設置上一個或者下一個嫌褪,但是發(fā)現(xiàn)這里執(zhí)行了方法呀枢,不意味著已經(jīng)跳轉到前一個或者后一個笼痛,僅僅是一個預處理,因此這里通過 let index = viewControllers.index(of: viewController)! 獲取當前的頁面在viewcontrollers數(shù)組中的位置,然后直接設置前一個界面|后一個界面

這里測試過程中發(fā)現(xiàn): 當我每次調(diào)用setViewControllers的時候,下一次滑動税迷,一定會分別執(zhí)行一次上面兩個方法县爬,大概是手動設置當前頁面之后,系統(tǒng)也蒙蔽了,所以要重新了解一下吧活尊。所以在這個方法里面就不能做太多的動作了

這里說一下 解決上面滑動過程中取消滑動漏益,pageIndex變化的問題蛹锰,在UIPageViewControllerDelegate 的方法中

//將要到--
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
    //提前設置頁碼數(shù)據(jù)绰疤,如果翻頁中途取消的話,在下面設置回去
    let finishOne = pendingViewControllers.first
    let index  = viewControllers.index(of: finishOne!)
    pageIndex = index!
    pageLabel.text = "\(index! + 1)/\(questions.count)"
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    //判斷是否成功轻庆,不成功,重新設置回去
    if !completed {
        //
        let finishOne = previousViewControllers.first
        
        let index  = viewControllers.index(of: finishOne!)
        pageIndex = index!
        pageLabel.text = "\(index! + 1)/\(questions.count)"
    }
}

這邊設置當前的頁碼余爆。更新UI纷宇,如果滑動為完成的話 complete 為false蛾方,這時候就要重新設置回去了上陕。這樣就解決了滑動過程中變化的問題--開始滑動就+1,滑動不成功再減回來M卮骸!

UIPageViewController自帶了單擊邊緣翻頁的效果硼莽,不想要辕万,因此干掉了

//MARK: 拓展UIPageViewController沉删,取消了邊緣的點擊事件
extension UIPageViewController: UIGestureRecognizerDelegate {

    /// 拓展一個方法醉途,取消UIPageViewController的點擊邊界翻頁
    fileprivate func cancleSideTouch() {
        for ges in gestureRecognizers {
            ges.delegate=self;
        }
    }
    
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        guard gestureRecognizer is UITapGestureRecognizer else {
            return true
        }
        return false
    }
}

檢查|統(tǒng)計答案的時候肯定需要實現(xiàn)一個遍歷數(shù)組的問題,推薦兩個方法隘擎,

public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]

public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

實現(xiàn)如下(僅供參考):

    let unDidAnswers = realAnswer.filter { (answer) -> Bool in
        return (answer.answer.isEmpty && answer.required == 1)
    }
    
    guard unDidAnswers.count == 0 else {
        print("any question required is not answerd")
        let firstUnDid = realAnswer.index(of: unDidAnswers.first!)
        let alert = UIAlertController(title: "存在未答題的必選項:\(firstUnDid! + 1)題", message: nil, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "繼續(xù)答題", style: .cancel, handler: nil))
        self.present(alert, animated: true, completion: {
            //
        })
        return
    }
    //.準備提交
    let results = realAnswer.map{["id": $0.questionId,"answer": $0.answer]}

主要代碼都在這了殴穴,如果找demo的話货葬,去github

都看到這了,說明真的用到了震桶,加了個復用的休傍,UIPageController實現(xiàn) 問卷蹲姐、試卷 2

雖然都很拙略,但也希望有些幫助

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柴墩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子江咳,更是在濱河造成了極大的恐慌逢净,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爹土,死亡現(xiàn)場離奇詭異,居然都是意外死亡东臀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門惰赋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呵哨,“玉大人,你說我怎么就攤上這事轨奄。” “怎么了挪拟?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵挨务,是天一觀的道長玉组。 經(jīng)常有香客問我,道長惯雳,這世上最難降的妖魔是什么朝巫? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任石景,我火速辦了婚禮,結果婚禮上潮孽,老公的妹妹穿的比我還像新娘揪荣。我一直安慰自己往史,他們只是感情好仗颈,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布揽乱。 她就那樣靜靜地躺著,像睡著了一般粟矿。 火紅的嫁衣襯著肌膚如雪凰棉。 梳的紋絲不亂的頭發(fā)上陌粹,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音掏秩,去河邊找鬼或舞。 笑死蒙幻,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的邮破。 我是一名探鬼主播诈豌,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼矫渔!你這毒婦竟也來了彤蔽?” 一聲冷哼從身側響起庙洼,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎油够,沒想到半個月后蚁袭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體石咬,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年碌补,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厦章。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖照藻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幸缕,我是刑警寧澤群发,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布发乔,位于F島的核電站,受9級特大地震影響栏尚,放射性物質(zhì)發(fā)生泄漏起愈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一抬虽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纵菌,春花似錦、人聲如沸咱圆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隘膘。三九已至疑故,卻和暖如春弯菊,著一層夾襖步出監(jiān)牢的瞬間纵势,已是汗流浹背管钳。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留才漆,地道東北人牛曹。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓醇滥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鸳玩。 傳聞我的和親對象是個殘疾皇子阅虫,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容