Skip to content

Create a Quiz UI

Maximilian Mackh edited this page Apr 17, 2020 · 9 revisions

Let's start with an annotated example of how to create a quiz UI, displaying a question, two buttons (answer A or answer B) and a submission button. BaseComponents used in this example: ControlClosures & SplitView.

//
//  QuizViewController.swift
//  BaseComponents Playground
//
//  Created by mmackh on 28.12.19.
//  Copyright © 2019 proconsult.at gmbh. All rights reserved.
//

import UIKit

import BaseComponents

class QuizViewController: UIViewController {

    // Variables for the UI components
    var splitView: SplitView?
    lazy var questionLabel: PerformLabel = {
        return PerformLabel("")
        .align(.center)
        .size(.title1, [.italic, .bold])
    }()
    lazy var answerA: UIButton = {
        return UIButton()
        .size(.title2)
        .addAction(for: .touchUpInside) { (button) in
            self.selectAnswer(button: button)
        }
    }()
    lazy var answerB: UIButton = {
        return UIButton()
        .size(.title2)
        .addAction(for: .touchUpInside) { (button) in
            self.selectAnswer(button: button)
        }
    }()
    
    // State
    var selectedAnswerButton: UIButton?
    var currentQuestion: Dictionary<String,String>?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        title = "Quiz Time!"
        view.backgroundColor = .white

        // Initiate root splitView - added unowed self to prevent retain cycles
        splitView = view.addSplitView(configurationHandler: { [unowned self] (splitView) in
            
            // add top padding to account for navigation bar
            splitView.insertSafeAreaInsetsPadding(form: splitView, paddingDirection: .top)
            
            // add question label with automatic sizing, depending on content, to splitView. added padding around the label for readability
            splitView.addSubview(self.questionLabel, layoutType: .automatic, edgeInsets: UIEdgeInsets(top: 20, left: 40, bottom: 20, right: 40))
            
            // add 2 buttons for selecting the answer, each with 50% of the remaining height of the splitView
            splitView.addSubview(self.answerA, layoutType: .percentage, value: 50)
            splitView.addSubview(self.answerB, layoutType: .percentage, value: 50)
            
            // add a submit button for checking the answer, height should be 54px
            let submitButton = UIButton(type: .system)
                .size(.title3, .bold)
                .text("Submit Answer")
                .text("Are you sure?", .highlighted)
                .color(.background, .gray, .highlighted)
                .addAction(for: .touchUpInside) { (control) in
                    self.submitAnswer()
                }
            splitView.addSubview(submitButton, layoutType: .automatic, edgeInsets: UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0))
            
            // add bottom padding to account for the home indicator, if present (this padding will default to 0 on iPhones/iPads with a home button)
            splitView.insertSafeAreaInsetsPadding(form: splitView, paddingDirection: .bottom)
            
        })
        nextQuestion()
    }
    
    var currentQuestionIdx: Int = -1
    let questions = [["que":"During good weather, the sky is usually...","a":"Blue","b":"Green","ans":"a"],
                     ["que":"Where is the city of Salzburg located?","a":"Austria","b":"Germany","ans":"a"],
                     ["que":"What UI framework is used to develop iOS apps nativly?","a":"CocoaTouch","b":"UIKit","ans":"b"],
                     ["que":"When it rains it ...","a":"pours","b":"waters the plants","ans":"b"]]
    
    func nextQuestion() {
        currentQuestionIdx += 1
        if (currentQuestionIdx > questions.count - 1) {
            currentQuestionIdx = 0
        }
        
        let question = questions[currentQuestionIdx]
        questionLabel.text(question["que"])
        answerA.text(question["a"])
        answerB.text(question["b"])
        currentQuestion = question
        
        UIView.animate(withDuration: 0.3) {
            self.splitView?.invalidateLayout()
            self.selectAnswer(button: nil)
        }
    }
    
    func selectAnswer(button: UIButton?) {
        answerA.color(.background, UIColor.blue.withAlphaComponent(0.1))
            .color(.text, .black)
        
        answerB.color(.background, UIColor.purple.withAlphaComponent(0.1))
            .color(.text, .black)
        
        button?.color(.background, button?.backgroundColor?.withAlphaComponent(1))
            .color(.text, .white)
        selectedAnswerButton = button
    }
    
    func submitAnswer() {
        if (selectedAnswerButton == nil) {
            return
        }
        
        let selectedButton: String = (selectedAnswerButton == answerA ? "a" : "b")
        let answeredCorrectly = (currentQuestion?["ans"] == selectedButton)
        
        let alertController = UIAlertController(title: "You answered", message: (answeredCorrectly ? "Correctly, well done!" : "Incorrectly. Try again in the next round!"), preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "Next Question", style: .default, handler: { [unowned self] (action) in
            self.nextQuestion()
        }))
        self.present(alertController, animated: true, completion: nil)
        
    }
}
Clone this wiki locally