公開中のアプリ

[Swift]StackViewとAutoLayoutをコードだけで実装する。

今回はstoryboardを使わずにコードだけでStackView(スタックビュー)とAutoLayout(オートレイアウト)を実装したいと思います。
いろいろな事情があり、StackViewに入れるボタンなどのオブジェクトをコードで自動生成している時などはstoryboardを使えないと思うのでコードで実装していくしかないと思います。

そんな時のヒントになれば嬉しいです。
完成イメージはこちらです。

今回のコードはこちら

先にコード全部載せておきたいと思います。
2.以降で部分的にコードを説明してるので是非ご覧下さい〜

class ViewController: UIViewController {
var stackV: UIStackView = UIStackView()
var buttonArray: [UIButton] = []
var stkArray: [UIStackView] = []
let mainView: UIView = UIView()

override func viewDidLoad() {
super.viewDidLoad()

//mainViewの背景色
mainView.backgroundColor = UIColor.gray
//AutosizingをAutoLayoutに変換しないようにしている
mainView.translatesAutoresizingMaskIntoConstraints = false
//ビューを表示させる
view.addSubview(mainView)
// 横方向の中心は親ビューの横方向の中心と同じ
mainView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
// 縦方向の中心は親ビューの縦方向の中心と同じ
mainView.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor).isActive = true
// mainViewの幅は親ビューの90%
mainView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.9).isActive = true
// mainViewの高さはmainViewの横幅と同じ。(正方形になる)
mainView.heightAnchor.constraint(equalTo: mainView.widthAnchor, multiplier: 1.0).isActive = true
//スタックビューを縦に設定
stackV.axis = .vertical
//中のオブジェクトをどこに揃えて配置するか決めている。
stackV.alignment = .fill
//縦にバランスよく配置
stackV.distribution = .fillEqually
//オブジェクト同士のスペース
stackV.spacing = 4
//おまじない
stackV.translatesAutoresizingMaskIntoConstraints = false
//stackVの背景色
stackV.backgroundColor = UIColor.white
//stackVを表示
view.addSubview(stackV)

//stackVの横方向の中心はmainViewの横方向の中心と同じ
stackV.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
//stackVの縦方向の中心はmainViewの縦方向の中心と同じ
stackV.centerYAnchor.constraint(equalTo: mainView.centerYAnchor).isActive = true
//stackVの横幅はmainViewの90%
stackV.widthAnchor.constraint(equalTo: mainView.widthAnchor, multiplier: 0.9).isActive = true
//stackVの高さはstackVの横幅と同じ。(正方形になる)
stackV.heightAnchor.constraint(equalTo: stackV.widthAnchor, multiplier: 1).isActive = true

//for文でStackView7つ生成
for i in 0 ..< 6 {
//StackViewの生成
let stackH:UIStackView = UIStackView()
//スタックビューを横に設定
stackH.axis = .horizontal
//オブジェクト同士のスペース
stackH.spacing = 4
//中のオブジェクトをどこに揃えて配置するか決めている。
stackH.alignment = .fill
//横にバランスよく配置
stackH.distribution = .fillEqually

//背景色を設定
switch i {
case 0:
stackH.backgroundColor = UIColor.systemPink
case 1:
stackH.backgroundColor = UIColor.systemPurple
case 2:
stackH.backgroundColor = UIColor.systemBlue
case 3:
stackH.backgroundColor = UIColor.systemYellow
case 4:
stackH.backgroundColor = UIColor.systemOrange
case 5:
stackH.backgroundColor = UIColor.systemGreen

default:
return
}
//スタックビュー配列に追加
stkArray.append(stackH)
}
//stackVの中にstackHを格納
for i in 0 ..< 6 {
stackV.addArrangedSubview(stkArray[i])
}

//ボタンを42個生成
var tagNumber = 1
for _ in 0...41 {
let button: UIButton = UIButton(type: .custom)
button.setTitleColor(UIColor.black, for: UIControl.State())
button.setTitle(String(tagNumber), for: UIControl.State())
button.tag = tagNumber
tagNumber += 1
buttonArray.append(button)
}

//生成したボタンをStackViewに格納
for i in 0 ..< 42 {
switch i {
case 0 ..< 7:
stkArray[0].addArrangedSubview(buttonArray[i] as UIView)
case 7 ..< 14:
stkArray[1].addArrangedSubview(buttonArray[i] as UIView)
case 14 ..< 21:
stkArray[2].addArrangedSubview(buttonArray[i] as UIView)
case 21 ..< 28 :
stkArray[3].addArrangedSubview(buttonArray[i] as UIView)
case 28 ..< 35:
stkArray[4].addArrangedSubview(buttonArray[i] as UIView)
case 35 ..< 42:
stkArray[5].addArrangedSubview(buttonArray[i] as UIView)
default:
return
}
}
}
}

メインビューの生成

まずはわかりやすいようにメインビューを作ってその中にStackViewを入れていきたいと思います。
ではコードを見て行きましょう。

class ViewController: UIViewController {

let mainView: UIView = UIView()

override func viewDidLoad() {
super.viewDidLoad()
    
//mainViewの背景色
mainView.backgroundColor = UIColor.gray
//AutosizingをAutoLayoutに変換しないようにしている
mainView.translatesAutoresizingMaskIntoConstraints = false
//ビューを表示させる
view.addSubview(mainView)
// 横方向の中心は親ビューの横方向の中心と同じ
mainView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true
// 縦方向の中心は親ビューの縦方向の中心と同じ
mainView.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor).isActive = true
// mainViewの幅は親ビューの90%
mainView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.9).isActive = true
// mainViewの高さはmainViewの横幅と同じ。(正方形になる)
mainView.heightAnchor.constraint(equalTo: mainView.widthAnchor, multiplier: 1.0).isActive = true
}

コードに書いてある通りなんですけど、3行目でビューを生成して14行目からAutoLayoutの設定になってます。
11行目はAutoLayoutを使う時は必ず書くおまじないだと思って大丈夫みたいです〜!
ビルドするとこんな感じ!

stackViewを生成(縦)

ではstackViewを作っていきたいと思います。
まずは縦方向のstackViewを作ります!
その縦の中に横方向のstackViewを入れるイメージです〜!
ではコードを見てみましょう!

//スタックビューを縦に設定
stackV.axis = .vertical
//中のオブジェクトをどこに揃えて配置するか決めている。
stackV.alignment = .fill
//縦にバランスよく配置
stackV.distribution = .fillEqually
//オブジェクト同士のスペース
stackV.spacing = 4
//おまじない
stackV.translatesAutoresizingMaskIntoConstraints = false
//stackVの背景色
stackV.backgroundColor = UIColor.white
//stackVを表示
view.addSubview(stackV)

//stackVの横方向の中心はmainViewの横方向の中心と同じ
stackV.centerXAnchor.constraint(equalTo: mainView.centerXAnchor).isActive = true
//stackVの縦方向の中心はmainViewの縦方向の中心と同じ
stackV.centerYAnchor.constraint(equalTo: mainView.centerYAnchor).isActive = true
//stackVの横幅はmainViewの90%
stackV.widthAnchor.constraint(equalTo: mainView.widthAnchor, multiplier: 0.9).isActive = true
//stackVの高さはstackVの横幅と同じ。(正方形になる)
stackV.heightAnchor.constraint(equalTo: stackV.widthAnchor, multiplier: 1).isActive = true

ビルドするとこんな感じ!
mainViewの中に綺麗に入りましたね!

stackViewを生成(横)

次は横のstackViewを作ります!
イメージいやすいように先に画像を載せます!
こんな感じです!

ではコードを見てみましょう!

//for文でStackView6つ生成
for i in 0 ..< 6 {
//StackViewの生成
let stackH:UIStackView = UIStackView()
//スタックビューを横に設定
stackH.axis = .horizontal
//オブジェクト同士のスペース
stackH.spacing = 4
//中のオブジェクトをどこに揃えて配置するか決めている。
stackH.alignment = .fill
//横にバランスよく配置
stackH.distribution = .fillEqually

//背景色を設定
switch i {
case 0:
stackH.backgroundColor = UIColor.systemPink
case 1:
stackH.backgroundColor = UIColor.systemPurple
case 2:
stackH.backgroundColor = UIColor.systemBlue
case 3:
stackH.backgroundColor = UIColor.systemYellow
case 4:
stackH.backgroundColor = UIColor.systemOrange
case 5:
stackH.backgroundColor = UIColor.systemGreen

default:
return
}
//スタックビュー配列に追加
stkArray.append(stackH)
}
//stackVの中にstackHを格納
for i in 0 ..< 6 {
stackV.addArrangedSubview(stkArray[i])
}

for文でStackView6つ生成しています。
ポイントは32行目から38行目です!
生成したstackHを配列のstkArrayに一度格納してから、一つずつ取り出してstackVの中に入れています。

ボタン生成&配置

次にボタンを生成して、そのボタンをstackHの中に入れます!
ちょっとややこしいですが、stackHは配列stkArrayの中に順番に入っている事を覚えておきましょう!
コードはこちらです!

//ボタンを42個生成
var tagNumber = 1
for _ in 0...41 {
let button: UIButton = UIButton(type: .custom)
button.setTitleColor(UIColor.black, for: UIControl.State())
button.setTitle(String(tagNumber), for: UIControl.State())
button.tag = tagNumber
tagNumber += 1
buttonArray.append(button)
}

//生成したボタンをStackViewに格納
for i in 0 ..< 42 {
switch i {
case 0 ..< 7:
stkArray[0].addArrangedSubview(buttonArray[i] as UIView)
case 7 ..< 14:
stkArray[1].addArrangedSubview(buttonArray[i] as UIView)
case 14 ..< 21:
stkArray[2].addArrangedSubview(buttonArray[i] as UIView)
case 21 ..< 28 :
stkArray[3].addArrangedSubview(buttonArray[i] as UIView)
case 28 ..< 35:
stkArray[4].addArrangedSubview(buttonArray[i] as UIView)
case 35 ..< 42:
stkArray[5].addArrangedSubview(buttonArray[i] as UIView)
default:
return
}
}

ポイントは13行目からです!
ボタンの数だけfor文を回して、7個ずつstackHに入れています!
stackHは配列stkArrayの中に入っているのでstkArray[0]のように書きます。

ビルドするとこうなります!

まとめ

いかがでしたでしょうか?
僕はカレンダーのアプリを作った時にこの方法で実装しました!
AutoLayoutってすぐ忘れちゃうのでメモがてら記事にしました〜!
わかりにくい所があれば気軽にコメント下さい!

コメントを残す

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

アプリ