サトリク
前回の講座を受けていない方はこちらから
- ◯×を表示させる約7分
- ◯×を0.5秒後に非表示にする約5分
- 選択肢のダブルタップを防ぐ約5分
今の状態
サトリク
今の状況としては、
- スタート画面でスタートを押すと、問題画面に遷移する
- 問題画面で選択肢を押すと、コンソール上で正誤判定が行われ、次の画面問題がセットされる
- 全ての問題を解くと、スコア画面に遷移する
- スコア画面に正解数が表示される
- 「トップに戻る」ボタンを押すとスタート画面に戻る
このPartでは、正解の場合は◯を表示し、不正解の場合は×を表示する機能をつけていきたいと思います!
![]()
◯×を表示させる
まずは、選択肢を押したら、正解の場合は◯を不正解の場合は×を表示させてみましょう。
Finderのダウンロードを開いて、先程ダウンロードしたimage.zipをダブルクリックで解凍しましょう。

以下のように、◯と×の画像が入っていることを確認しましょう。

プロジェクトにインポートしましょう。

画像のように、imageフォルダをプロジェクト(SampleQuizフォルダの中)にドラッグ&ドロップしてください。
以下の画像のように設定してください。

①Copy items if neededにチェック
②Create groupsにチェック
③SampleQuizにチェック
④「Finish」をクリック
Copy items if neededにチェックを入れないややめんどくさいことになります。

左のメニューからMain.storyboardを選択してください。
問題画面にImageViewを配置しましょう。

①右上のプラスボタンをクリック
②ImageViewを問題画面にドラッグ&ドロップ

①ImageViewを選択
②
(Show the Size inspector)を選択
③X、Y、Width、Heightを以下のようにする。
| X | 20 |
| Y | 100 |
| Width | 374 |
| Height | 374 |

①問題画面のバーをクリック
②command + option + control + enterで2分割表示

controlを押しながら、ドラッグ&ドロップ

NameにjudgeImageViewと入力し、Connect

左のメニューからQuizViewController.swiftを選択してください。
ボタンを押した時に呼ばれるブロック内で、正解だったら紐付けたjudgeImageViewに◯の画像を代入し、不正解だったら×の画像を代入するコードを追記しましょう。
@IBAction func btnAction(sender: UIButton) {
if sender.tag == Int(quizArray[1]) {
correctCount += 1
print("正解")
judgeImageView.image = UIImage(named: "correct")
} else {
print("不正解")
judgeImageView.image = UIImage(named: "incorrect")
}
print("スコア:\(correctCount)")
nextQuiz()
}


このように選択肢を押したら、正解だったら◯不正解だったら×が表示されるはずです。
これで◯×の表示ができました。
しかし、◯×がずっと表示されたままです。0.5秒経ったら非表示にする処理を追記しましょう。
◯×を0.5秒後に非表示にする
次は、◯×を0.5秒経ったら非表示にする処理を付け加えていきましょう。
〇〇秒後に処理をしたい場合は、以下のように書きます。
この場合だと、judgeImageView(◯×)のisHidden(隠すかどうか)をtrue(隠す)にしている処理を0.5秒後におこないます。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.judgeImageView.isHidden = true
}


このように、ボタンを押したら非表示になりました。
が、しかし2問目の選択肢を押しても◯×が出なくなりました。
2問目以降表示されないのは、judgeImageView.isHidden = trueにしたせいです。要は◯×の画像を隠している状態だからです。
なので、ボタンを押したら、◯×の画像を再表示する処理を追記してあげましょう。
@IBAction func btnAction(sender: UIButton) {
if sender.tag == Int(quizArray[1]) {
correctCount += 1
print("正解")
judgeImageView.image = UIImage(named: "correct")
} else {
print("不正解")
judgeImageView.image = UIImage(named: "incorrect")
}
print("スコア:\(correctCount)")
judgeImageView.isHidden = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.judgeImageView.isHidden = true
}
nextQuiz()
}


そうするとこのように、2問目以降の問題でも◯×が表示されると思います。
これで、◯×を0.5秒後に非表示する処理ができました。
選択肢のダブルタップを防ぐ
少し説明が難しいのですが、現状、選択肢をトントンとダブルタップすると、問題文や選択肢が表示する前に次の問題が解かれてしまいます。
なので以下の対応をします。
- ◯×が非表示になってから、次の問題をセットする
- 選択肢を押してから◯×が非表示になるまでボタンを押せなくする
この対応は簡単です。
次の問題をセットするブロックnextQuiz()を0.5秒後に表示させるブロックに移動させるだけです。
で、0.5秒後に表示させるブロック内ではself.を付けないといけないので、以下のようにselfをつけて記述してください。
@IBAction func btnAction(sender: UIButton) {
if sender.tag == Int(quizArray[1]) {
correctCount += 1
print("正解")
judgeImageView.image = UIImage(named: "correct")
} else {
print("不正解")
judgeImageView.image = UIImage(named: "incorrect")
}
print("スコア:\(correctCount)")
judgeImageView.isHidden = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.judgeImageView.isHidden = true
self.nextQuiz()
}
}

実行して確認してみましょう。
おそらく、◯×が非表示になった瞬間に次の問題がセットされるようになっているはずです。
ボタンを押したら、ボタンを押せなくしましょう。
押せなくするには、answerButton1のisEnabled(有効かどうか)をfalse(無効)にします。
@IBAction func btnAction(sender: UIButton) {
if sender.tag == Int(quizArray[1]) {
correctCount += 1
print("正解")
judgeImageView.image = UIImage(named: "correct")
} else {
print("不正解")
judgeImageView.image = UIImage(named: "incorrect")
}
print("スコア:\(correctCount)")
judgeImageView.isHidden = false
answerButton1.isEnabled = false
answerButton2.isEnabled = false
answerButton3.isEnabled = false
answerButton4.isEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.judgeImageView.isHidden = true
self.nextQuiz()
}
}

ImageViewのisHiddenと反対の動きをするので、isHiddenとisEnabledの違いに注意してください。
| コード | 意味 | true時 | false時 |
|---|---|---|---|
isHidden |
隠すかどうか | 隠す | 隠さない |
isEnabled |
有効にするかどうか | 有効にする | 無効にする |

実行して選択肢ボタンを押すとこのようにボタンが機能しなくなります。
このままでは、2問目の問題が解けないので、◯×が非表示になったらまたボタンが機能するようにしましょう。
やり方は簡単で、0.5秒経ったら有効にすればいいだけです。
0.5秒経ったら実行されるブロックに以下のように記述してください。
@IBAction func btnAction(sender: UIButton) {
if sender.tag == Int(quizArray[1]) {
correctCount += 1
print("正解")
judgeImageView.image = UIImage(named: "correct")
} else {
print("不正解")
judgeImageView.image = UIImage(named: "incorrect")
}
print("スコア:\(correctCount)")
judgeImageView.isHidden = false
answerButton1.isEnabled = false
answerButton2.isEnabled = false
answerButton3.isEnabled = false
answerButton4.isEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.judgeImageView.isHidden = true
self.answerButton1.isEnabled = true
self.answerButton2.isEnabled = true
self.answerButton3.isEnabled = true
self.answerButton4.isEnabled = true
self.nextQuiz()
}
}

これで2回目以降も問題が解けるようになります。
これでpart6の◯×を表示する処理は完成です!
ここまでの全コード
QuizViewController.swift
import UIKit
class QuizViewController: UIViewController {
@IBOutlet var quizNumberLabel: UILabel!
@IBOutlet var quizTextView: UITextView!
@IBOutlet var answerButton1: UIButton!
@IBOutlet var answerButton2: UIButton!
@IBOutlet var answerButton3: UIButton!
@IBOutlet var answerButton4: UIButton!
@IBOutlet var judgeImageView: UIImageView!
var csvArray: [String] = []
var quizArray: [String] = []
var quizCount = 0
var correctCount = 0
override func viewDidLoad() {
super.viewDidLoad()
csvArray = loadCSV(fileName: "quiz")
print(csvArray)
quizArray = csvArray[quizCount].components(separatedBy: ",")
quizNumberLabel.text = "第\(quizCount + 1)問"
quizTextView.text = quizArray[0]
answerButton1.setTitle(quizArray[2], for: .normal)
answerButton2.setTitle(quizArray[3], for: .normal)
answerButton3.setTitle(quizArray[4], for: .normal)
answerButton4.setTitle(quizArray[5], for: .normal)
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let scoreVC = segue.destination as! ScoreViewController
scoreVC.correct = correctCount
}
//ボタンを押したときに呼ばれる
@IBAction func btnAction(sender: UIButton) {
if sender.tag == Int(quizArray[1]) {
correctCount += 1
print("正解")
judgeImageView.image = UIImage(named: "correct")
} else {
print("不正解")
judgeImageView.image = UIImage(named: "incorrect")
}
print("スコア:\(correctCount)")
judgeImageView.isHidden = false
answerButton1.isEnabled = false
answerButton2.isEnabled = false
answerButton3.isEnabled = false
answerButton4.isEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.judgeImageView.isHidden = true
self.answerButton1.isEnabled = true
self.answerButton2.isEnabled = true
self.answerButton3.isEnabled = true
self.answerButton4.isEnabled = true
self.nextQuiz()
}
}
func nextQuiz() {
quizCount += 1
if quizCount < csvArray.count {
quizArray = csvArray[quizCount].components(separatedBy: ",")
quizNumberLabel.text = "第\(quizCount + 1)問"
quizTextView.text = quizArray[0]
answerButton1.setTitle(quizArray[2], for: .normal)
answerButton2.setTitle(quizArray[3], for: .normal)
answerButton3.setTitle(quizArray[4], for: .normal)
answerButton4.setTitle(quizArray[5], for: .normal)
} else {
performSegue(withIdentifier: "toScoreVC", sender: nil)
}
}
func loadCSV(fileName: String) -> [String] {
let csvBundle = Bundle.main.path(forResource: fileName, ofType: "csv")!
do {
let csvData = try String(contentsOfFile: csvBundle,encoding: String.Encoding.utf8)
let lineChange = csvData.replacingOccurrences(of: "\r", with: "\n")
csvArray = lineChange.components(separatedBy: "\n")
csvArray.removeLast()
} catch {
print("エラー")
}
return csvArray
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
この後のクイズアプリ講座について
サトリク
お疲れ様でした!ここまでうまくできましたか?
初心者の方が、アプリ開発の知識を身につけるには、まず、リリースしてみることです。
初心者の方でまだ何もアプリをリリースしたことがない人は、このクイズアプリをリリースしましょう。当然このままだとリリースできないので、もう少し機能を付け足しましょう。
この先の講座では、よりリリースできるようなアプリを目指して作っていきます。
- ジャンル選択機能
- ランダムで出題機能
- シェア機能
- レイアウトをよくする
- AutoLayoutをつける
- バナー広告をつける
- 起動画面の作成
- リリース手順
サトリク
Part7以降では、zennというサイトで有料で行っていきます。
一緒に楽しく雑談しながらアプリ開発しませんか?

RikutoSato
自分一人でリリースできるか不安という方に向けて、このブログの筆者でもある自分が、MENTAというサービスを使って月額4000円で皆さんのクイズアプリをAppStoreにリリースするまで、全力でサポートします。
以下の内容でやっています。
- Part7まで無料公開します。←当たり前ですが。。
- AppStoreにリリースできるまでサポートします。
- あなたのやりたい機能の実装をサポートします。
- 不明点をなど質問し放題です。(24時間以内に返信実際は(一瞬で返します))
- 理解不能だったらビデオチャットで画面を映して解説します。
- Slack、アプリ開発グループに招待します。
気軽にご相談ください!
このクイズアプリ講座で、実際にリリースまでできたアプリ
Kさん:Generation Quiz
10月13日〜12月8日と、大体2ヶ月でリリースできました!
BGMや、時間制限、スコア保存、広告など、いろいろな機能を追加しました。



