公開中のアプリ

[Swift/Xcode]初心者必見!iOSアプリ作成から公開まで徹底解説!#08 「ラベルをコードで実装編」

今回は貯金額と日数を表示する為のラベルをコードで実装したいと思います。

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

今回は下記動画のところまで実装します。

下準備

本題に入る前にナビゲーションコントローラーまわりの色とか変更しておきます!
viewDidLoad()に下記を追加して下さい!

//ナビゲーションコントローラーまわり
//タイトル
self.title = "365貯金"
//背景色
self.navigationController?.navigationBar.barTintColor = UIColor.orange
//セーフエリアとの境目の線を消す
self.navigationController?.navigationBar.shadowImage = UIImage()
//上部が黒くなるのを回避
view.backgroundColor = UIColor.systemBackground

ラベルを入れるビューを生成

まずラベルを作る前にラベルを入れるビューを作りたいと思います。

流れとしては、
ナビゲーションコントローラーのすぐ下に同じ色(オレンジ)のビュー生成。
そのビューの中に更に白いビュー生成。
白いビューの中に二つのラベルを生成します。

まずはそれぞれの部品を用意します。

//オレンジ色のビュー
let topView: UIView = UIView()
//白色のビュー
let topViewInner: UIView = UIView()

次にそれぞれのレイアウトを設定するんですけど
その前にわかりやすくする為、スクロールビュー部分(ボタン、インビューも含む)を全部コメントアウトしておきました。

ビューのコードは下記になります。
viewCreateメソッドの中に書いて下さいね〜!

//オレンジのビューのレイアウト
//AutosizingをAutoLayoutに変換しないようにしている(おまじない)
topView.translatesAutoresizingMaskIntoConstraints = false
//X軸
topView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
//Y軸
topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
//横幅
topView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 1).isActive = true
//縦幅
topView.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.125).isActive = true
//背景色
topView.backgroundColor = UIColor.orange

//白色のビューのレイアウト
//(おまじない)
topViewInner.translatesAutoresizingMaskIntoConstraints = false
//X軸
topViewInner.centerXAnchor.constraint(equalTo: topView.centerXAnchor).isActive = true
//Y軸
topViewInner.centerYAnchor.constraint(equalTo: topView.centerYAnchor).isActive = true
//横幅
topViewInner.widthAnchor.constraint(equalTo: topView.widthAnchor, multiplier: 0.9).isActive = true
//縦幅
topViewInner.heightAnchor.constraint(equalTo: topView.heightAnchor, multiplier: 0.75).isActive = true
//背景色
topViewInner.backgroundColor = UIColor.white

オレンジ色のビューはセーフエリアを基準にオートレイアウトの設定をして
白色のビューはオレンジ色のビューを基準にオートレイアウトの設定をしています。

ビルドするとこんな感じです!

ラベルの生成

では白色のビューにラベルを入れたいと思います。

まずはラベルを用意します。

//合計日数のラベル
let dayLabel: UILabel = UILabel()
//貯金額のラベル
let moneyLabel: UILabel = UILabel()

次にラベル表示用のメソッドを作ってそこにラベルをレイアウトなどを
書いていきたいと思います。

func labelCreate() {
    //合計日数のラベルを表示
    topViewInner.addSubview(dayLabel)
    //貯金額のラベルを表示
    topViewInner.addSubview(moneyLabel)
    
    //合計日数のラベルのレイアウト
    //(おまじない)
    dayLabel.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    dayLabel.leftAnchor.constraint(equalTo: topViewInner.leftAnchor, constant: 20.0).isActive = true
    //Y軸
    dayLabel.centerYAnchor.constraint(equalTo: topViewInner.centerYAnchor).isActive = true
    //ラベルのテキスト
    dayLabel.text = "\(whatDay)日目"

    //貯金額のラベルのレイアウト
    //(おまじない)
    moneyLabel.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    moneyLabel.rightAnchor.constraint(equalTo: topViewInner.rightAnchor, constant: -20.0).isActive = true
    //Y軸
    moneyLabel.centerYAnchor.constraint(equalTo: topViewInner.centerYAnchor).isActive = true
    //ラベルのテキスト
    moneyLabel.text = "合計貯金額 \(totalSavings)円"
}

特に難しいところはないのですが、説明するならば11行目でしょうか。

ラベルの左側は白色のビューの左側から20ポイントの位置に
表示させると言う意味です。

続いてviewDidLoad()の中を下記に変更します!

override func viewDidLoad() {
    super.viewDidLoad()
    //ビューの生成
    viewCreate()
    //ラベルの生成
    labelCreate()
    //ボタンの生成
    btnCreate()
    //スタックビューの生成
    stackViewCreate()
}

これでビルドすると下記画像のようになっているはずです!

スクロールビューの位置を変更

あとは、スクロールビューを再度表示させればいいんですけど、
このまま表示してしまうとオレンジのビューとかぶってしまうので
スクロールビューの位置を下げます!

スクロールビューのオートレイアウトを下記コードに修正します。

//スクロールビューの設定
//AutosizingをAutoLayoutに変換しないようにしている(おまじない)
scrollView.translatesAutoresizingMaskIntoConstraints = false
//スクロールビューの上側の位置を設定
scrollView.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: 20.0).isActive = true
//スクロールビューの下側の位置を設定
scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20.0).isActive = true
//Y軸
scrollView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
//横幅
scrollView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 0.9).isActive = true

コードに書いてある通りですが、
スクロールビューの上側の位置と下側の位置を指定する事によって
スクロールビューの高さを決定しています。

これでビルドするとこんな感じです!

今回のコード全部

うまくいきましたか??
最後に今までのコードを全部載せておきますのでこれをコピペしちゃえば
パウっと解決です!

import UIKit

class MainViewController: UIViewController {

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

//オレンジ色のビュー
let topView: UIView = UIView()
//白色のビュー
let topViewInner: UIView = UIView()
//合計日数のラベル
let dayLabel: UILabel = UILabel()
//貯金額のラベル
let moneyLabel: UILabel = UILabel()

    
override func viewDidLoad() {
    super.viewDidLoad()
    //ビューの生成
    viewCreate()
    //ラベルの生成
    labelCreate()
    //ボタンの生成
    btnCreate()
    //スタックビューの生成
    stackViewCreate()
    
    //ナビゲーションコントローラーまわり
    //タイトル
    self.title = "365貯金"
    //背景色
    self.navigationController?.navigationBar.barTintColor = UIColor.orange
    //セーフエリアとの境目の線を消す
    self.navigationController?.navigationBar.shadowImage = UIImage()
    //上部が黒くなるのを回避
    view.backgroundColor = UIColor.systemBackground
}


//ビュー生成
func viewCreate() {
    //オレンジ色のビューの表示
    view.addSubview(topView)
    //白色のビューの表示
    topView.addSubview(topViewInner)
    //スクロールビューの表示
    view.addSubview(scrollView)
    //ボタン表示用ビューの表示
    scrollView.addSubview(inView)

    //スクロールビューの設定
    //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    //スクロールビューの上側の位置を設定
    scrollView.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: 20.0).isActive = true
    //スクロールビューの下側の位置を設定
    scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20.0).isActive = true
    //Y軸
    scrollView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
    //横幅
    scrollView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, 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
        
        
    //オレンジのビューのレイアウト
    //AutosizingをAutoLayoutに変換しないようにしている(おまじない)
    topView.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    topView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
    //Y軸
    topView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
    //横幅
    topView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 1).isActive = true
    //縦幅
    topView.heightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.heightAnchor, multiplier: 0.125).isActive = true
    //背景色
    topView.backgroundColor = UIColor.orange

    //白色のビューのレイアウト
    //(おまじない)
    topViewInner.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    topViewInner.centerXAnchor.constraint(equalTo: topView.centerXAnchor).isActive = true
    //Y軸
    topViewInner.centerYAnchor.constraint(equalTo: topView.centerYAnchor).isActive = true
    //横幅
    topViewInner.widthAnchor.constraint(equalTo: topView.widthAnchor, multiplier: 0.9).isActive = true
    //縦幅
    topViewInner.heightAnchor.constraint(equalTo: topView.heightAnchor, multiplier: 0.75).isActive = true
    //背景色
    topViewInner.backgroundColor = UIColor.white
    }

//ラベル生成
func labelCreate() {
    //合計日数のラベルを表示
    topViewInner.addSubview(dayLabel)
    //貯金額のラベルを表示
    topViewInner.addSubview(moneyLabel)
    
    //合計日数のラベルのレイアウト
    //(おまじない)
    dayLabel.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    dayLabel.leftAnchor.constraint(equalTo: topViewInner.leftAnchor, constant: 20.0).isActive = true
    //Y軸
    dayLabel.centerYAnchor.constraint(equalTo: topViewInner.centerYAnchor).isActive = true
    //ラベルのテキスト
    dayLabel.text = "\(whatDay)日目"

    //貯金額のラベルのレイアウト
    //(おまじない)
    moneyLabel.translatesAutoresizingMaskIntoConstraints = false
    //X軸
    moneyLabel.rightAnchor.constraint(equalTo: topViewInner.rightAnchor, constant: -20.0).isActive = true
    //Y軸
    moneyLabel.centerYAnchor.constraint(equalTo: topViewInner.centerYAnchor).isActive = true
    //ラベルのテキスト
    moneyLabel.text = "合計貯金額 \(totalSavings)円"
}
    
//ボタン生成
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(MainViewController.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

    dayLabel.text = "\(whatDay)日目"
    moneyLabel.text = "合計貯金額\(totalSavings)円"
}

//スタックビュー生成
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
        }
    }
}
}

まとめ

今回でちょっと形になってきたかと思います!
次はどこを実装しようかまだ考え中です(^^;

あ!オートレイアウトでエラーが出ちゃう場合、ビューを表示する順番
とかに気をつけてみて下さい!

まだaddSubviewで表示していないのにオートレイアウトでそのビューの指定とか書いちゃうとエラーになります。
例えば下記のコードだとエラーになります!

//スクロールビューの表示
view.addSubview(scrollView)
//スクロールビューの設定
//AutosizingをAutoLayoutに変換しないようにしている(おまじない)
scrollView.translatesAutoresizingMaskIntoConstraints = false
//スクロールビューの上側の位置を設定
scrollView.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: 20.0).isActive = true
//スクロールビューの下側の位置を設定
scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -20.0).isActive = true
//Y軸
scrollView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
//横幅
scrollView.widthAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.widthAnchor, multiplier: 0.9).isActive = true

//オレンジ色のビューの表示
view.addSubview(topView)

この場合オレンジ色のビューをまだ表示させていないのに
スクロールビューのオートレイアウトにオレンジ色のビューが出てきちゃってますよね?
こういう時は16行目を3行目あたりに持って来ると解決します!

ここまで読んでくれた人、本当に感謝です!
なんでも良いのでコメントくれると嬉しいです!
間違ってるところとか指摘してくれると助かります!
お願いします!

コメントを残す

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

アプリ