今回は、画面遷移(画面の切り替え)時に、配列を渡し、テーブルビュー(TableView)に表示する方法をご紹介します。1つの値のみではなく、配列に入れた値全てを渡します。また、Timerメソッドを活用します。言葉では分かりにくいと思いますので、完成形のイメージ動画を最初にご確認下さい。
チェック
1つの値を画面遷移先に渡す基本方法は、下記の記事をご参考下さい。
今回は、画面遷移(画面の切り替え)の方法をご紹介します。また、画面遷移で遷移先に値を渡す方法と条件が達成されると自動で画面遷移する方法も組み入れました。ご紹介する内容では、1つの値を渡していますが、値を渡せるようになると[…]
- 1 完成形のイメージ
- 2 1. ストーリーボードにパーツを準備(1)〜(9)
- 3 ViewControllerのコード
- 4 2. viewDIdLoadより上で準備する内容
- 5 3. viewDidLoad内のコード
- 6 4. Timerクラスのスケジュールタイマーの設定
- 7 5. スタートボタンの設定
- 8 6. ストップボタンの設定
- 9 7. 結果ボタンの設定(画面遷移)
- 10 NextViewControllerのコード
- 11 8. viewDidLoadより上で準備する内容
- 12 9. viewDidLoad内のコード
- 13 10. 正解率の計算
- 14 11. テーブルビューの設定
- 15 12. 「戻る」ボタンの設定
- 16 全コード
完成形のイメージ
まず最初に、今回ご紹介するコードで出来上がった完成形を動画にしました。全コードは、ページ最後に載せています。
1. ストーリーボードにパーツを準備(1)〜(9)
(1) 画像の準備
始めに、使用する画像を準備します。画像4つとスタートボタンとストップボタンの合計6つを準備しました。その画像を、Assets.xcassets内に入れることで、Xcode内で使用できるようになります。
(2) 2つ目の画面の準備
次に、画面遷移先の画面を作成します。右上の+ボタンからViewControllerを追加します。画面内のスタートボタンやストップボタンは無視して下さい。後から、説明します。
(3) swiftファイルを準備
追加した画面(下の図の右側のView Controller)には、名前が付いておらず、また対応したswiftファイルもありません。そこで、ファイルを作成します。
- tableViewTest2021.07フォルダで右クリック
- NewFile…を左クリック
- Cocoa Touch Classを選択し、Nextボタンを左クリック
- Class名にNextViewControllerと入力し、SubclassはUIViewController、Languageはswift、年Nextボタンを左クリック
- さらにCreateボタンを左クリック
ファイルの作成ができたと思います。
次に、Controllerに名前を付けるため、右側のView Controllerの上の白いバーのところを左クリックすると、画面右にCustom Classが表示されます。ここのClassに作成したファイル名と同じ、NextViewControllerと入力して下さい。
(4) ViewControllerにパーツを準備
次に、ViewControllerにパーツを準備します。
- ImageView(イメージビュー) 1つ
- 表示する画像は、プログラムで指定するので、このままでOK。
- TextView(テキストビュー) 1つ
- 画像を止めた時に、当たりとはずれを表示する場所。こちらは、Backgroundカラーを透明色とします。表示する文字は、プログラムで指定します。
- Button(ボタン) 3つ
- スタートとストップは準備した画像を貼ります。
(5) ViewControllerのパーツをコードを繋ぐ
次に、先ほど準備したパーツとプログラムを繋ぎます。Control+左クリック⇨コードにドラッグで繋がります。パーツを繋ぐとき、アクション以外は、viewDidLoadより上にドラッグして下さい。変数の宣言もviewDidLoadより上に記述することが多く、まとめておくことで、見やすくなります。
そして、アクション内容は、viewDidLoadより下にドラッグして下さい。
viewDidLoadは、最初からコードに記述されています。ここは、アプリが起動した時に動くコードを記述箇所です。
(6) NextViewControllerにパーツを準備
次に、NextViewControllerのパーツを準備します。重ねる順番も大事ですので、作成順に必要なパーツを列記します。
- TableView(テーブルビュー) 1つ
- サイズは適当で良いですが、パーツを上に載せていくため、最初に作成します。
- Button(ボタン) 1つ
- 戻るボタンの作成。
- TableViewCell(テーブルビューセル) 1つ
- テーブルビューの上に1つ置きます。横幅はテーブルビューと同じ広さにします。高さはプログラムで指定しますが、一応60にしています。
- Label(ラベル) 4つ
- 2つは、背景の上に設置。
- もう2つは、テーブルビューセルの上に設置。
- imageView(イメージビュー) 1つ
- テーブルビューセルの上に設置。
(7) NextViewControllerのパーツの設定
次に、テーブルビューセル内のラベルとイメージビューに関して、設定します。
- ImageViewのサイズは60✖️60とします。(プログラムでセルの高さを60としますので、ImageViewも60のサイズにしました。)
- TableVIewCellをクリックし、右側のプロパティーから、identifierに名前をつけます。 Cell と入力します。
- テーブルビューセル内の3つのパーツ(ラベルとイメージビュー)にタグをつけます。
(8) NextViewControllerのパーツとコードを繋ぐ
次に、パーツとプログラムを繋ぎます。ViewControllerの時と同じように、アクションは、viewDidLoadより下に配置します。また、タグ付けをした3つのパーツは、プログラムで識別するため、ここでは、パーツとプログラムを繋ぎません。
(9) 画面遷移の準備
次に、画面遷移の下準備をします。
左のViewControllerの上の白いバーにある一番左のアイコンのところから、Control+左クリックを押し、ドラッグで右のNextViewControllerに繋ぎます。そうすると、2つの画面の真ん中が矢印で繋がります。
繋がった矢印を左クリックし、右側のプロパティーのStoryboard Segueのidentifierに、nextと入力します。これで、画面遷移の下準備が完了です。
ViewControllerのコード
2. viewDIdLoadより上で準備する内容
- @IBOutletは、ストーリーボードのパーツとコードを繋いだものです。
- 16行目のタイマーは、タイマークラスの中のscheduledTimerメソッドを利用するために、ここで宣言します。(scheduledTimer:指定時間ごとに、プログラムを動かすメソッド)
- 17行目のcountは、計算用に使うため、Int型で宣言します。
- 20行目は、UIImage型(画像ファイル)を入れる配列を宣言。(準備した4枚の画像を入れるための配列)
- 23行目は、ストップボタンで、止まった時の画像が、何番の画像かを取得するための配列。
- 24行目は、正解した数を数えるために、Int型の変数を宣言。
- 27,28行目は、当たりとハズレが出た時に表示する文字列を、ここで準備しています。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var stopButton: UIButton!
@IBOutlet weak var senyiButton: UIButton!
var timer = Timer()
var count = Int()
//画像を表示するための配列
var imageArray = [UIImage]()
//結果を収集し、テーブルに表示させるための配列
var resultArray = [String]()
var correctAnswerCount = 0
//当たりとはずれが出た時に表示する文字
var hittext = "当たり!"
var nohittext = "惜しい(>.<)"
3. viewDidLoad内のコード
- 6、7行目は、結果ボタンをsenyiButtonとしてコードにつなぎましたが、このボタンの角を丸めるためのコードです。
- 10行目は、アプリ起動時に、ストップボタンを押せない状態にするコードです。
- 13〜17行目は、画像ファイルをimageという変数に入れ、それから、imageArrayの配列に入れています。for関数を使うことで、iに0、1、2、3の4つの数字を代入し、その数字を画像ファイルの文字列としての0、1、2、3に当てはめ、imageArrayにアペンドしています。
- 20行目は、imageViewの初期画像を指定しています。ストーリーボード上で画像を入れていませんので、ここで指定します。
override func viewDidLoad() {
super.viewDidLoad()
count = 0
senyiButton.layer.cornerRadius = 10.0
senyiButton.clipsToBounds = true
//ストップボタンを押せなくする
stopButton.isEnabled = false
//0,1,2,3と名付けた画像をimageArrayにアペンド
for i in 0..<4 {
let image = UIImage(named: "\(i)")
imageArray.append(image!)
}
//アプリが立ち上がったときに最初に表示する画像
imageView.image = UIImage(named: "0")
}
4. Timerクラスのスケジュールタイマーの設定
タイマーを使う場合、セレクターとセレクターで指定するメソッド(@objc func)を作成します。
- 1行目、スケジュールタイマーの内容を簡単なコードで使えるようにファンクションを作成ます。
- 3行目、timeIntervalは、何秒毎にコードを実行するかを指定します。また、#selector内のtimeChangeは、セレクターで指定するメソッドのファンクション名です。
- 6行目で、セレクターで指定するファンクションを作成しています。
- 7〜9行目、4枚の画像を0.05秒ずつ切り替えて表示させるのですが、ファイル名は0、1、2、3の4つしかありません。カウントが4より大きくなったら0に戻すようにしています。
- 11行目、imageArrayにはUIImage型の4枚の画像が入っています。配列には先頭から0番目、1番目、2番目、3番目と番号が振られています。この番号はInt型ですので、ここの11行目で指定する番号もInt型で指定します。すると、その番号に合う画像をimageViewに表示してくれます。
func start(){
timer = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(timeChange), userInfo: nil, repeats: true)
}
@objc func timeChange(){
count = count + 1
if count > 3{
count = 0
}
imageView.image = imageArray[count]
}
5. スタートボタンの設定
では、スタートボタンが押された時のアクション内容を作成します。
- 2行目、start()は作成したファンクションをここで使用します。4. で作成したスケジュールタイマーの内容がこの1行で実行できます。
- 3行目、当たりとはずれを表示するtextViewを空にします。
- 5、6行目、スタートボタン押されたら、ストップボタンを押せるようにする必要があります。ここで、スタートボタンをfalse、ストップボタンをtrueにすることで、推せるボタンを切り替えています。
@IBAction func startAction(_ sender: Any) {
start()
textView.text = ""
startButton.isEnabled = false
stopButton.isEnabled = true
}
6. ストップボタンの設定
次に、ストップボタンが押された時のアクション内容を作成します。
- 5、6行目、ストップボタンが押されたので、次にスタートボタンを押せるように、スタートボタンをtrue、ストップボタンをfalseとします。
- 9行目、画像が、0.05秒毎に切り替わっていたので、ここでスケジュールタイマーを停止させます。
- 11〜15行目、カウントが0の時のアクション内容を指定します。カウント0というのは、当たり画像で画面がストップした時となります。
- 12行目、textViewに表示する文字を、2. で準備した文字列に指定します。
- 13行目、文字の色を青色に指定。
- 14行目、画面が止まった時のカウント番号を結果の配列に入れます。(resultArray:遷移画面後のテーブルビューに表示する結果)
- 15行目、正解率を出すために、当たりの0を引いた時に、+1します。
- 17〜20行目、カウント0でない時のアクションを指定します。ハズレの画像でストップした時に、こちらのコードが動きます。
- 18行目、ハズレの文字を表示します。nothittextは2. で準備した文字列。
- 19行目、文字の色を赤に指定。
- 20行目、resultArrayの配列に結果を入れます。(”1″ or “2” or “3”の文字列が入ります)
@IBAction func stopAction(_ sender: Any) {
//startButtonを押せるようにする
startButton.isEnabled = true
stopButton.isEnabled = false
//タイマーを止める
timer.invalidate()
if count == 0 {
textView.text = hittext
textView.textColor = UIColor.blue
resultArray.append(String(count))
correctAnswerCount = correctAnswerCount + 1
}else{
textView.text = nohittext
textView.textColor = UIColor.red
resultArray.append(String(count))
}
print(resultArray)
}
7. 結果ボタンの設定(画面遷移)
値を渡す画面遷移は、下記のようにコードします。形として覚えておくと便利です。
- 2行目、withIdentifierに”next”とありますが、Storyboard Segueで指定した名前を入力します。
- 6行目、遷移先のファイル名をNextViewControllerとして作成しました。それをnexrVCという名前で使用するように宣言しています。
- 8、9行目、ストップを押した時のカウントの結果をresultArrayに、正解した数をcorrectAnswerCountに入れていきました。これらの結果を、NextViewControllerで作成する変数に入れます。(resultArray2とcorrectAnswerCount2は、NextViewControllerで宣言するまでは、エラーが出ますが、ここでは無視でOKです。)
@IBAction func senyiButtonAction(_ sender: Any) {
performSegue(withIdentifier: "next", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let nextVC = segue.destination as! NextViewController
nextVC.resultArray2 = resultArray
nextVC.correctAnswerCount2 = correctAnswerCount
}
NextViewControllerのコード
8. viewDidLoadより上で準備する内容
- 3行目、テーブルビューを利用するため、UITableViewDelegateとUITableViewDataSourceを追記します。
- 5、6行目、ここで結果を受け取る変数を宣言します。このコードを書くことで、ViewControllerのエラーが消えます。
- IBOutletは、ストーリーボードとパーツをコードで繋いだものです。
import UIKit
class NextViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var resultArray2 = [String]()
var correctAnswerCount2 = 0
@IBOutlet weak var correctAnswerRate: UILabel!
@IBOutlet weak var tableView: UITableView!
9. viewDidLoad内のコード
- 4、5行目、テーブルビューを利用するためのコードです。
- 9行目、正解率を計算するファンクションをNextViewControllerが表示されたら実行します。(ファンクションは、後で作成します)
- (7行目と11行目のprintは、結果を見るためのものですので、削除してもOKです)
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
print(correctAnswerCount2)
correctRate()
print("結果:", resultArray2)
}
10. 正解率の計算
- 3、4行目、結果が全くない時は、正解率を表示しないようにしています。このコードがないと、アプリ起動後、すぐに結果ボタンを押すとエラーとなるためです。
- 5〜7行目、ここは、単純に、正解した数÷結果の総数から正解率を出しています。ですが、Int型は整数型のため、正解率が正確に出ません。そこで、Duoble型に切り替えて計算し、1000倍して、roundで小数点以下を四捨五入して、1000で割っています。
//正解率の計算
func correctRate(){
if resultArray2.count == 0{
correctAnswerRate.text = "---"
}else{
let rate = Double(correctAnswerCount2) / Double(resultArray2.count)
correctAnswerRate.text = String(round(1000 * rate) / 1000 * 100) + " %"
}
}
11. テーブルビューの設定
テーブルビューを利用する際、少なくとも下記3つのファンクションを準備します。
- 2〜3行目、テーブルに表示する行数を何行にするかを決めます。ここでは、結果の配列に含まれる個数分欲しいので、resultArray2.countと指定しました。
- 6〜7行目、テーブルビュー内のセルの高さを指定します。
- 10〜33行目、ここでテーブルビュー内のセルに表示する情報を指定します。
-
- 11行目、テーブルビューのセルにつけた名前を指定します。 ”Cell”
- 13〜15行目、タグ付けした3つのパーツを、それぞれ扱いやすいように宣言。
- 17行目、テーブルビューに入るデータはindexPath.rowで番号指定できるため、1番からの数字を並べたいので、+1にしてlabelTag1に表示。
- 19〜23行目、resuleArray2の結果のデータに”0″があると当たりですので、当たりの時のコードを準備。文字、文字色、バックカラーの指定、image画像の指定をしています。
- 24〜27行目、ハズレの時のコードを準備。文字、文字色、image画像の指定をしています。
//テーブルビューの設定
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultArray2.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let labelTag1 = cell.contentView.viewWithTag(1) as! UILabel
let labelTag2 = cell.contentView.viewWithTag(2) as! UILabel
let imageTag3 = cell.contentView.viewWithTag(3) as! UIImageView
labelTag1.text = String(indexPath.row + 1)
if resultArray2[indexPath.row] == "0"{
labelTag2.text = "当たり"
labelTag2.textColor = UIColor.blue
imageTag3.image = UIImage(named: "0")
cell.backgroundColor = UIColor.cyan
}else{
labelTag2.text = "惜しい"
labelTag2.textColor = UIColor.red
imageTag3.image = UIImage(named: String(resultArray2[indexPath.row]))
}
return cell
}
12. 「戻る」ボタンの設定
最後に、戻るボタンのアクションの設定をします。このまま記述していただければ、ViewControllerに戻ることができます。
@IBAction func backButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
全コード
ViewController
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var startButton: UIButton!
@IBOutlet weak var stopButton: UIButton!
@IBOutlet weak var senyiButton: UIButton!
var timer = Timer()
var count = Int()
//画像を表示するための配列
var imageArray = [UIImage]()
//結果を収集し、テーブルに表示させるための配列
var resultArray = [String]()
var correctAnswerCount = 0
//当たりとはずれが出た時に表示する文字
var hittext = "当たり!"
var nohittext = "惜しい(>.<)"
override func viewDidLoad() {
super.viewDidLoad()
count = 0
senyiButton.layer.cornerRadius = 10.0
senyiButton.clipsToBounds = true
//ストップボタンを押せなくする
stopButton.isEnabled = false
//0,1,2,3と名付けた画像をimageArrayにアペンド
for i in 0..<4 {
let image = UIImage(named: "\(i)")
imageArray.append(image!)
}
//アプリが立ち上がったときに最初に表示する画像
imageView.image = UIImage(named: "0")
}
func start(){
timer = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(timeChange), userInfo: nil, repeats: true)
}
@objc func timeChange(){
count = count + 1
if count > 3{
count = 0
}
imageView.image = imageArray[count]
}
@IBAction func startAction(_ sender: Any) {
start()
textView.text = ""
startButton.isEnabled = false
stopButton.isEnabled = true
}
@IBAction func stopAction(_ sender: Any) {
//startButtonを押せるようにする
startButton.isEnabled = true
stopButton.isEnabled = false
//タイマーを止める
timer.invalidate()
if count == 0 {
textView.text = hittext
textView.textColor = UIColor.blue
resultArray.append(String(count))
correctAnswerCount = correctAnswerCount + 1
}else{
textView.text = nohittext
textView.textColor = UIColor.red
resultArray.append(String(count))
}
}
@IBAction func senyiButtonAction(_ sender: Any) {
performSegue(withIdentifier: "next", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let nextVC = segue.destination as! NextViewController
nextVC.resultArray2 = resultArray
nextVC.correctAnswerCount2 = correctAnswerCount
}
}
NextViewController
import UIKit
class NextViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var resultArray2 = [String]()
var correctAnswerCount2 = 0
@IBOutlet weak var correctAnswerRate: UILabel!
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
print(correctAnswerCount2)
correctRate()
print("結果:", resultArray2)
}
//正解率の計算
func correctRate(){
if resultArray2.count == 0{
correctAnswerRate.text = "---"
}else{
let rate = Double(correctAnswerCount2) / Double(resultArray2.count)
correctAnswerRate.text = String(round(1000 * rate) / 1000 * 100) + " %"
}
}
//テーブルビューの設定
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultArray2.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let labelTag1 = cell.contentView.viewWithTag(1) as! UILabel
let labelTag2 = cell.contentView.viewWithTag(2) as! UILabel
let imageTag3 = cell.contentView.viewWithTag(3) as! UIImageView
labelTag1.text = String(indexPath.row + 1)
if resultArray2[indexPath.row] == "0"{
labelTag2.text = "当たり"
labelTag2.textColor = UIColor.blue
imageTag3.image = UIImage(named: "0")
cell.backgroundColor = UIColor.cyan
}else{
labelTag2.text = "惜しい"
labelTag2.textColor = UIColor.red
imageTag3.image = UIImage(named: String(resultArray2[indexPath.row]))
}
return cell
}
@IBAction func backButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}