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

この記事は公開されてから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みたいな使い方も出来ます。個人的には等間隔に並べたい時に凄く手軽になったと思いました。

  • famtom

    viewDidLayoutSubviewsの中でaxisを変更する際にメインスレッドで実行しているのはなぜでしょうか?