問卷App-測你是漫威哪位超級英雄

這次除了問卷資料傳遞外,結合PageViewController挑戰看看!

進入測驗
重測

|架構

上面PageViewController跟三個ViewController做頁面滑動,像是有些App前導頁,下面兩個畫面分別是測驗頁面跟結果頁面。

PageViewController

在StoryBoard找到PageViewController拉出來很開心地想要創Class,但在Cocoa Touch Class怎麼找怎麼找就是沒有PageViewController,由上滑到下到滑回最上面,沒有,確定不是眼殘。不過沒關係,我們可以先選ViewController,在檔案裡修改繼承的Class就可以啦。

CustomPageViewController後面改成我要的PageViewController

接著就能回到StoryBoard選Class了。在Transition Style預設值是像書本那樣的翻頁效果的Page Curl,我想要滑動效果,選擇Scroll

一開始先建立頁面陣列,這裡用三個ViewController建立的,先將它們塞進去,也當作變數宣告。

var subViewControllers: [UIViewController] = {
return[
UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "First") as! IntoViewController,
UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "Second") as! Into01ViewController,
UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "Third") as! Into02ViewController]
}()

在ViewDidLoad設定頁面初始值。

setViewControllers([subViewControllers[0]], direction: .forward, animated: true, completion: nil)

接著在Class添加UIPageViewControllerDataSource跟UIPageViewControllerDelegate。出現一定要實作的function- viewControllerBefore viewController跟ViewControllerAfter viewController,

Before設定如果當前頁面最前頁不能往前繼續滑,如果不是可以往前滑。

After設定到陣列最後一個位置不能繼續,反之可以。

func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex: Int = subViewControllers.firstIndex(of: viewController) ?? 0
if currentIndex <= 0 {
return nil
}
return subViewControllers[currentIndex - 1]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex: Int = subViewControllers.firstIndex(of: viewController) ?? 0
if currentIndex >= subViewControllers.count - 1 {
return nil
}
return subViewControllers[currentIndex + 1]
}

添加小圓點也可以呼叫function完成。

presentationCount輸入總共有幾個頁面,presentationIndex指滑到哪一頁圓點會在當前頁面反白。return 0的0代表第一頁的索引值也就是在[subViewControllers[0]]。

func presentationCount(for pageViewController: UIPageViewController) -> Int {
return subViewControllers.count
}

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
return 0
}

skipButton和startButton單純的用performSegue跳至測驗主畫面。

@IBAction func skip(_ sender: UIButton) {performSegue(withIdentifier: "Into01ToQ", sender: nil)}

QuestionViewController

因為問題很多,所以要先開Swift設定問題跟答案。比較特別的是number用來記錄選到的答案分數,做統計用。

struct Hero {
let question: String
let answer: [String]
let number: [Int]
}

題目是網路上找的,有些題目字數太長所以稍做修飾,後來不像原本的題目,所以不附連結。總共15題。

questions = [Hero(question: "上一次別人叫你帥哥/美女是什麼時候?", answer: ["陌生人向你搭訕的時候","好久不見的朋友誇獎你","放在社圖軟體的修圖得到讚美","逛街時,店員招呼你的時候"], number: [1,2,3,4]),
Hero(question: "“你一定能答對這道題!”請問這個論斷是正確的嗎?", answer: ["正確,我一定可以答對","我說對就對啦","錯誤,我不知道這題的意思","你...說...什...麼"], number: [1,2,3,4]),
Hero(question: "你覺得Apple Watch的售價怎麽樣?", answer: ["不知道,別人送的","不知道,反正買不起","不知道,不想用","買了一個,不要問你會怕"], number: [1,2,3,4]),
Hero(question: "你喜歡用電動剃刀還是刮刀來刮鬍子/刮腿毛呢?", answer: ["用鑷子拔","電動的","手動的","沒長鬍子/腿毛"], number: [1,2,3,4]),
Hero(question: "你怎麽看旅途中的艷遇?", answer: ["相信佛系豔遇法","電影才會發生的情節","旅行的意義就是豔遇","很自然的事情"], number: [1,2,3,4]),
Hero(question: "你後面有輛車猛按喇叭,這時你打算?", answer: ["不跟他一般見識","下次看到我就OOO","揍他","想像對方原地爆炸的樣子"], number: [1,2,3,4]),
Hero(question: "感覺身邊的朋友長得好看嗎?", answer: ["對,我拉高平均值","是的,習慣他們的長相","客觀來看他們一樣醜","看膩了"], number: [1,2,3,4]),
Hero(question: "在好朋友的聚會上碰上了一個不熟悉但十分討厭的人,你會?", answer: ["找他麻煩","臭臉但什麼都不會做","不理他","觀察他,重新檢視之前的判斷"], number: [1,2,3,4]),
Hero(question: "捐舊衣服導致消費力下降,你怎麽看?", answer: ["這世界不會好了","我依然覺得做了一件好事","那我不捐衣服了","不要問我辣"], number: [1,2,3,4]),
Hero(question: "喜歡玩命關頭7嗎?", answer: ["一個字爽","為了保羅沃克去看的","不喜歡這類電影","劇情普通,車子很炫"], number: [1,2,3,4]),
Hero(question: "已知2+2=魚,3+3=無限,那麽7+7等於什麽?", answer: ["圓圈","狗","金牛","三角形"], number: [1,2,3,4]),
Hero(question: "你做過被搶劫或破產的夢嘛?害怕嗎?", answer: ["我沒什麼好搶的","有,錢都飛走了","還真的沒有","做過,錢沒了再賺就好啊"], number: [1,2,3,4]),
Hero(question: "給你一台電腦一年不出門。一年後會發生什麽?", answer: ["死了","靠著外送跟電視劇過生活","成為超級駭客","我現在就是"], number: [1,2,3,4]),
Hero(question: "和喜歡的異性玩競賽類遊戲,你會怎樣做?", answer: ["贏他,讓他知道我的實力","故意輸,讓他開心","幹嘛玩競賽遊戲","享受遊戲,輸贏無所謂"], number: [1,2,3,4]),
Hero(question: "你做了個奇怪的夢,你能想起來這個夢嗎?", answer: ["從來不記得","能記得還叫夢?","一定跟我最近想的是有關","怎麼證明我現在醒著"], number: [1,2,3,4]),
]

用for迴圈撈每個選項。

questionLabel.text = questions[0].questionfor (i, answerButton) in answerButtons.enumerated() {answerButton.setTitle(questions[0].answer[i], for: .normal)}

在選項按鈕Action裡計算選到答案的number並計算每一題題數。如果走到地15題會跳至結果頁。

//計算分數if let numberString = sender.restorationIdentifier,let number = Int(numberString) {totalNumber += numberprint("計算值\(totalNumber)")}//增加題數questionNumber += 1if questionNumber < 15 {questionLabel.text = questions[questionNumber].questionfor (i,answerButton) in answerButtons.enumerated() {answerButton.setTitle(questions[questionNumber].answer[i], for: .normal)}}else if questionNumber == 15 {performSegue(withIdentifier: "ToAnswer", sender: nil)}

把計算總分傳到下一頁用Segue,因為有多個按鈕,拉Segue的時候直接拉到答案頁的controller。

@IBSegueAction func chooseAnswer(_ coder: NSCoder,sender: Any?, segueIdentifier: String?) -> AnswerViewController? {let controller = AnswerViewController(coder: coder)controller?.totalNumber = totalNumberreturn controller}

AnswerViewController

這頁比較簡單,在viewDidLoad設定totalNumber分數範圍顯示測驗結果就好。在這裡依照不同結果,圖片邊框跟文字背景的顏色做出區別,黑寡婦文字背景用預設值,所以沒設定。

if totalNumber <= 20 {resultLabel.text = "黑寡婦"heroImageView.image = UIImage(named: "BlackWidow")heroImageView.layer.borderColor = UIColor(named: "BlackWidowC")?.cgColordescribeLabel.text = """果斷的你有著跟黑寡婦一樣讓人不可置信的狠勁外,更重要的應該是有陰險謀略的腦袋。"""}else if totalNumber > 20 , totalNumber <= 25{resultLabel.text = "美國隊長"heroImageView.image = UIImage(named: "CaptainAmerica")heroImageView.layer.borderColor = UIColor(named: "CaptainAmericaC")?.cgColordescribeLabel.backgroundColor = UIColor(named: "CaptainAmericaC")describeLabel.text = """與美國隊長相似的你,應該也是一個骨子裏很懷舊的人,正直到有點頑固,不管過去受過什麽傷,要往前看哦!"""}else if totalNumber > 25, totalNumber <= 35{resultLabel.text = "鷹眼"heroImageView.image = UIImage(named: "HulkEye")heroImageView.layer.borderColor = UIColor(named: "HulkEyeC")?.cgColordescribeLabel.backgroundColor = UIColor(named: "HulkEyeC")describeLabel.text = """你是一個理想的夥伴,忠誠、真誠,同時還是一個知道自己目標努力達成的人。"""}else if totalNumber > 35, totalNumber <= 45{resultLabel.text = "鋼鐵人"heroImageView.image = UIImage(named: "IronMan")heroImageView.layer.borderColor = UIColor(named: "IronManC")?.cgColordescribeLabel.backgroundColor = UIColor(named: "IronManC")describeLabel.text = """和鋼鐵人一樣,你也是高智商物種,而且很可能從小衣食無憂,異性緣也很好……我還能說什麽,求認識!"""}else if totalNumber > 45, totalNumber <= 55{resultLabel.text = "雷神索爾"heroImageView.image = UIImage(named: "Thor")heroImageView.layer.borderColor = UIColor(named: "ThorC")?.cgColordescribeLabel.backgroundColor = UIColor(named: "ThorC")describeLabel.text = """雷神選中的你,大概也和他一樣不食人間煙火吧。現實中總有事和你想象的不一樣,但是沒關係,你足夠強大,能應付這一切的。"""}else if totalNumber > 55{resultLabel.text = "浩克"heroImageView.image = UIImage(named: "Hulk")heroImageView.layer.borderColor = UIColor(named: "HulkC")?.cgColordescribeLabel.backgroundColor = UIColor(named: "HulkC")describeLabel.text = """說不好你更像綠巨人還是班納,也許他們每一個都是你,別擔心,精分兒童歡樂多~但是適當控制情緒對你有好處哦~"""}

回到題目頁面我用unwind segue,unwind segue要設定在想回去的頁面,

寫一個segueAction。在答案頁面replayButton拉線到exit,完成連線。

重新開始要記錄重置,所有的問題用shuffle的方式隨機出現。

@IBAction func unwindBack(_ segue: UIStoryboardSegue){totalNumber = 0questionNumber = 0questions.shuffle()}

記錄一下Button加邊框(borderWidth)會直接切齊文字,想要邊框增加距離可以contentEdgeInsets。

replayButton.layer.borderWidth = 2replayButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)replayButton.layer.borderColor = UIColor.white.cgColor

參考資源

--

--