サトリク
前回の講座を受けていない方はこちらから
- ◯×を表示させる約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や、時間制限、スコア保存、広告など、いろいろな機能を追加しました。