公開中のアプリ

[Swift/Xcode]初心者必見!iOSアプリ作成から公開まで徹底解説!#06 「ボタンアクション実装編」

今回はボタンをタップした時に何かしらの処理をする機能を実装したいと思います。

動作環境は下記の通りです!
Xcode Version 12.5 Swift version 5.4

今回の実装内容

ここで今回作成するアプリの機能の確認をしておきたいと思います。
作るアプリは365日貯金なので、1円〜365円の中から一つ選んで貯金します。
貯金したら金額を忘れないようにその金額のボタンを押してもらう事になります。
そして、「今まで貯金した合計金額」と「貯金を初めて何日目か」を表示させる必要もありましたね。

アニメーションも付けたいと思っていますが一旦置いといて、
とりあえずボタンを押したらボタンの色を変更して、貯金額と何日目かをプリントで出力させたいと思います。
※貯金は1日1回なので、例えばボタンを4回タップしたら4日目と表示させるようにしたいと思います。

動画見た方が早いですね(^^;
出力したテキストが動画だと見えにくいのでご自身で確認してもらえたらと思います。

先にコード全部載せておきます!
コピペでOKです!

import UIKit

class ViewController: UIViewController {

    //スクロールビュー
    let scrollView = UIScrollView()
    //ボタンを表示用のビュー
    let inView: UIView = UIView()
    //スタックビュー縦用
    var stackV: UIStackView = UIStackView()
    //ボタンの配列
    var buttonArray: [UIButton] = []
    //スタックビュー横を格納する為の配列
    var stkArray: [UIStackView] = []
    //貯金額合計
    var totalSavings = 0
    //貯金開始?日目
    var whatDay = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        
        //ビューの生成
        viewCreate()
        //ボタンの生成
        btnCreate()
        //スタックビューの生成
        stackViewCreate()
    }
    
    //ビュー生成
    func viewCreate() {
        //スクロールビューの表示
        view.addSubview(scrollView)
        //ボタン表示用ビューの表示
        scrollView.addSubview(inView)
        
        //スクロールビューの設定
        //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        //X軸
        scrollView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
        //Y軸
        scrollView.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor).isActive = true
        //横幅
        scrollView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 0.9).isActive = true
        //縦幅
        scrollView.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.9).isActive = true

        //ボタン表示用ビューの設定
        //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
        inView.translatesAutoresizingMaskIntoConstraints = false
        //横幅
        inView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 1.0).isActive = true
        //この4つの制約をつけて初めてスクロールするっぽい
        inView.leftAnchor.constraint(equalTo: scrollView.leftAnchor, constant: 0).isActive = true
        inView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 0.0).isActive = true
        inView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 0.0).isActive = true
        inView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0.0).isActive = true
    }
    
    //ボタン生成
    func btnCreate() {
        //ボタンの生成と設定
        //ボタンにtagを付ける為の変数
        var tagNumber = 1
        //for文でボタンを生成
        for _ in 0...364 {
            //ボタン生成
            let button: UIButton = UIButton(type: .custom)
            //タイトルの色
            button.setTitleColor(UIColor.black, for: UIControl.State())
            //タイトルは数字なのでtagナンバーを指定
            button.setTitle(String(tagNumber), for: UIControl.State())
            //tag設定
            button.tag = tagNumber
            //背景色
            button.backgroundColor = UIColor.lightGray
            //ボーダーの横幅
            button.layer.borderWidth = 3
            //ボターの色
            button.layer.borderColor = UIColor.black.cgColor
            //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
            button.translatesAutoresizingMaskIntoConstraints = false
            //ボタンの横幅が可変なのでボタンの高さは横幅と同じ長さを指定する事で正方形にしてる。
            button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0).isActive = true
            //変数tagNumberに1追加
            tagNumber += 1
            // タップされたときのaction
            button.addTarget(self, action: #selector(ViewController.buttonTapped(_:)), for: .touchUpInside)
            //ボタンの配列に追加
            buttonArray.append(button)
        }
    }
    
    //365ボタンをタップした時の処理
    @objc func buttonTapped(_ sender : UIButton) {
        
        totalSavings += sender.tag
        whatDay += 1
        print("貯金開始\(whatDay)日目 貯金額\(totalSavings)円")
        buttonArray[sender.tag - 1].backgroundColor = UIColor.red
    }
    
    //スタックビュー生成
    func stackViewCreate() {
        //スタックビュー縦の設定
        //スタックビューの方向を縦に
        stackV.axis = .vertical
        //中のオブジェクトをどこに揃えて配置するか
        stackV.alignment = .fill
        //どう配置するか
        stackV.distribution = .fill
        //オブジェクト同士のスペース
        stackV.spacing = 4
        //おまじない
        stackV.translatesAutoresizingMaskIntoConstraints = false
        //stackVの背景色
        stackV.backgroundColor = UIColor.white
        //stackVを表示
        inView.addSubview(stackV)
        //X軸
        stackV.centerXAnchor.constraint(equalTo: inView.centerXAnchor).isActive = true
        //トップ位置
        stackV.topAnchor.constraint(equalTo: stackV.topAnchor, constant: 0.0).isActive = true
        //横幅
        stackV.widthAnchor.constraint(equalTo: inView.widthAnchor, multiplier: 1.0).isActive = true
        //縦幅
        stackV.heightAnchor.constraint(equalTo: inView.heightAnchor, multiplier: 1.0).isActive = true

        //スタックビュー横を自動生成
        for i in 0 ..< 73 {
            //StackHの生成
            let stackH:UIStackView = UIStackView()
            //スタックビューの方向を横に
            stackH.axis = .horizontal
            //オブジェクト同士のスペース
            stackH.spacing = 4
            //中のオブジェクトをどこに揃えて配置するか
            stackH.alignment = .fill
            //どう配置するか
            stackH.distribution = .fillEqually
            //スタックビュー配列に追加
            stkArray.append(stackH)
            //stackVの中にstackHを格納
            stackV.addArrangedSubview(stkArray[i])
        }

        //ボタンの配置
        //for文のカウンター変数
        var count = 0
        //for文で365個のボタンをどのstackHに入れるか決めている
        for i in 1 ..< 366 {
            //カウントの数に応じてどのstackHに入るか決定する。
            stkArray[count].addArrangedSubview(buttonArray[i - 1] as UIView)
            //ボタンは5列なので5の倍数でcountを一つ増やす。
            if i % 5 == 0 {
                count += 1
            }
        }
    }
    
}

addTargetメソッドを使う

addTargetメソッドはボタンをタップした時に何かしらの処理をしてくれるメソッドです!
ボタン生成時にこの機能も付けておきたいので、btnCreate()メソッドの中に組み込んでしまいます!
該当コードは下記コードの29行目です!

//ボタン生成
func btnCreate() {
    //ボタンの生成と設定
    //ボタンにtagを付ける為の変数
    var tagNumber = 1
    //for文でボタンを生成
    for _ in 0...364 {
        //ボタン生成
        let button: UIButton = UIButton(type: .custom)
        //タイトルの色
        button.setTitleColor(UIColor.black, for: UIControl.State())
        //タイトルは数字なのでtagナンバーを指定
        button.setTitle(String(tagNumber), for: UIControl.State())
        //tag設定
        button.tag = tagNumber
        //背景色
        button.backgroundColor = UIColor.lightGray
        //ボーダーの横幅
        button.layer.borderWidth = 3
        //ボターの色
        button.layer.borderColor = UIColor.black.cgColor
        //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
        button.translatesAutoresizingMaskIntoConstraints = false
        //ボタンの横幅が可変なのでボタンの高さは横幅と同じ長さを指定する事で正方形にしてる。
        button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0).isActive = true
        //変数tagNumberに1追加
        tagNumber += 1
        // タップされたときのaction
        button.addTarget(self, action: #selector(ViewController.buttonTapped(_:)), for: .touchUpInside)
        //ボタンの配列に追加
        buttonArray.append(button)
    }
}

29行目のbuttonTappedはメソッド名なので任意です。
ボタンが押された時にこのメソッドの処理をしてくれます。
そのメソッドが下記部分です。

//365ボタンをタップした時の処理
@objc func buttonTapped(_ sender : UIButton) {
    totalSavings += sender.tag
    whatDay += 1
    print("貯金開始\(whatDay)日目 貯金額\(totalSavings)円")
    buttonArray[sender.tag - 1].backgroundColor = UIColor.red
}

このメソッドの説明をする前に、追加した変数があるのでまずそれを確認しておきます。
最初にコード全部載せましたが、それの16行目と18行目が今回追加した変数です。
コードにも書いてますが、
変数totalSavings → 貯金額の合計
変数whatDay → 何日目か

ではbuttonTappeメソッドの説明をします!

まず3行目です。
例えば5円のボタンが押されたら、5円のボタンが持ってるtag番号は5なので、5を変数totalSavingsに足す処理をしています。

4行目はボタンが押されたら変数whatDayに1を足してます。

5行目は貯金額の合計と何日目かを出力してます。

6行目は押されたボタンの色を赤に変更しています。
自動生成されたボタンは、配列buttonArrayに365個格納されています。
なので5円が押されたらbuttonArrayの5番目のボタンの色を変更すれば良いんですね!

ここで押さえておきたいポイントは、配列buttonArrayは0から順番にインデックス番号が割り振られているのに対して、ボタンのtag番号は1から始まっています。
配列buttonArrayのインデックス番号にtag番号の5を指定しちゃうと、一つズレてしまいます。
なのでbuttonArray[sender.tag – 1]として、tag番号から1を引く事でインデックス番号とtag番号を合わせてます。

まとめ

ボタンにタップ機能を付ける事ができました!
ここまでいかがでしょうか?
ちょっとでもアプリを作る参考になれば嬉しいです!

次回はどうしましょうか??
とりあえず「貯金額合計」と「何日目か」をラベルで表示しましょうかね。
それだけだとすぐ終わっちゃいそうなのでナビゲーションコントローラーも付けるかもしれません。

読んでくれた人ありがとうございます。
コメント欲しいです( ˙-˙ )

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

アプリ