[iOS 9] UIStackViewを知らない人向けの基礎知識

2016.01.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

この内容は昨年6月に北海道で開催した『Developers.IO Meetup 11 in Sapporo』でUIStackViewについて発表した内容を、(すごく今更感はありますが)再度Blogにまとめたものです。 元のスライドはiOS9が発表された直後に書いたので内容が薄いUIStackViewを知らない人向けの内容になってます。

UIStackViewとは

UIStackViewは、縦または横に並べる用のレイアウトになります。AndroidでいうところのLinearLayoutのようなイメージです。

UIStackViewが登場する前

UIStackViewが登場する前には均等に横に並べるようなレイアウトを作るには、間にSpacerのUIViewを入れて制約たくさんつける必要があり、ちょっと面倒でした。

ios9_uistackview1

※ SpacerViewを配置する方法は公式ドキュメントに記載されていた方法です。

ios9_uistackview1.5

(参考:Auto Layout ガイド - ビューを等間隔で並べる (P.31)
)

UIStackViewを使用して配置する

UIStackViewを使用して等間隔に配置すると、ボタンなどのsubview自体の制約が不要になります。 よって制約自体が少なくなって、作成するのが楽になります。 下記画像では、UIStackViewは画像下のボタン部分に使用してます。

ios9_uistackview2

UIStackViewの使い方

StoryboardでStackViewを配置する方法

サンプルとして↑に載せている、きりんのレイアウトを作るまでの手順です。

1.Image Viewを配置します

ios9_uistackview3

2.Image Viewに制約をつけます

ここでは、上左右を0、高さを230にしてます。またわかりやすいように画像もセットしておきました。

ios9_uistackview4

3.Stack Viewを配置します

今回は横に並べるため Horizontal Stack View を使用しました。

ios9_uistackview5

4.Stack View自体に制約をつけます

StackView自体の位置やサイズの調整です。上:ImageViewから0、左右:0、高さを60にしました。

ios9_uistackview6

5.Stack Viewのプロパティを修正します

今回は等間隔にしたいのでDistributionFill Equallyにしました。

ios9_uistackview7

尚、stack view の配置は以下のプロパティに基づきます。

プロパティ名 説明
axis レイアウトの軸(垂直or水平)
distribution レイアウトの分布
alignment 垂直のレイアウト
spacing View間の最小間隔

6.ボタンを配置します

StackView内にボタンを配置します。画像も一緒にセットしておきます。

ios9_uistackview8

7.Text Viewを配置して制約をつけます

ios9_uistackview9

上記の手順でレイアウト配置は完成です

ios9_uistackview10

Stack View Tips

縦と横で並べ方を変更する

端末の向きを変えた時にそのままだと並べ方は変わりません。下記図では、端末を横にしても縦並びのままです。 ios9_uistackview11

それを、端末を横にした時は横並びにするには、StackViewをOutlet接続しコード上でaxisを変更します。

override func viewDidLayoutSubviews()
{
   super.viewDidLayoutSubviews()
        
   dispatch_async(dispatch_get_main_queue())
   {
      if self.view.frame.height > self.view.frame.width {
         // 縦方向に並べる
         self.mainStackView.axis = UILayoutConstraintAxis.Vertical
      } else {
         // 横方向に並べる
         self.mainStackView.axis = UILayoutConstraintAxis.Horizontal
      }
   }
}

上記処理を入れると端末が縦の時は縦並びに、横にした時は横並びになります。

ios9_uistackview12

SubViewsの数を変化させる

下記イメージのようにボタンを押した時にSubViewの数を変更させるには、hiddenを切り替えるだけで自動的に最適なレイアウトになります。

ios9_uistackview13

 @IBAction func didTapPlusButton(sender: UIButton)
    {
        for subview in self.mainStackView.arrangedSubviews { 
            if subview.hidden
            {
                subview.hidden = false
                break
            }
        }
    }
    
    @IBAction func didTapMinusButton(sender: UIButton)
    {
        for subview in self.mainStackView.arrangedSubviews {
            if !subview.hidden
            {
                subview.hidden = true
                break
            }
        }
    }

また、上記は表示/非表示で切替えてましたが、subViewを生成して増やしても自動的に最適なレイアウトになります。

//subviewを追加する(最後に追加)
self.stackView.addArrangedSubview( subview )
//subviewを追加する(任意の位置に追加/↓は先頭)
self.stackView.insertArrangedSubview(subview, 0)
//subviewを削除する
self.stackView.removeArrangedSubview( subview )

たくさん追加すると下記イメージのように増えます。

ios9_uistackview14

Stack View の中に Stack View を入れる

下記イメージのようにStackViewは入れ子にすることが出来ます。

ios9_uistackview15

さいごに

並び方の向きをプロパティ1つで切替えられたり、hiddenでレイアウトを自動的に切替えるのが便利です。また、AndroidのView.GONEみたいな使い方も出来ます。個人的には等間隔に並べたい時に凄く手軽になったと思いました。