[iOS9] UIStackViewの事例紹介

2016.02.02

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

1 UIStackViewとは

UIStackViewとは、iOS9から追加されたもので、縦または横方向に子Viewを自動的に配置する機能を有しているコンポーネントです。

Androidでは、LinearLayout、WindowsPhoneでは、StackPanel、Xamarinでは、StackLayoutと言う感じで、既に、色々なフレームワークであたり前のように存在していたので、「えっ無かったの?」というのが、私の第一印象です。

実際に使ってみるとすぐに気が付きますが、「制約」の数が非常に少なくなり、Storyboard上もかなりスッキリさせることができます。

このような、便利なコンポーネントですが、iOS9以降でしか使用できないことから、まだ、事例としてはあまり使用されていないというのが現状ではないでしょうか。

使い方などについては、既に、各所で紹介されているので、今回は、実際に使用してみた事例として、その使いどころや、気づいた事項を紹介しようと思います。

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

[iOS9]UIStackViewについて

2 勇者のポモドーロタイマー

今回、UIStackViewを使用して作成されたアプリは、次のようなものです。

001

ポモドーロテクニックとは、例えば、「25分集中して5分休む」というように、タスクを分割して繰り返すことで、「効率」や「達成感」を上げるという作業方法の一つです。

イタリア式時間管理術「ポモドーロテクニック」とは??

今回作成したアプリは、このポモドーロテクニックで作業する場合に、それを支援するタイマーです。 作業に集中している間は、画面上で「勇者」が次々と登場するモンスターと戦っており、途中で諦めることなく、一つのタスクをやり遂げるごとに、トマトをゲットできたり、集めたコインで、武器を強化できたりという達成感を助長するアプリとなっています。

作業と、休憩の終了時には、通知が送られ、Apple Watchなどがあれぱ、更に快適に利用することができると思います。

20160201090642

上記は、Apple Watchで見た、「勇者のポモドーロタイマー」からの通知です。

3 画面設計

概要を検討している段階で、各機能に、どのようなコントロールを配置するかについては、一通り決定しましたが、どこでUIStackViewを使用するかについては、決まっていませんでした。 今回はまだ、UIStackViewに不慣れなため、Storyboard上で画面をレイアウトする中で、逐次、最適な方法を検討する事にしたのです。

002

003

そして、結果的にUIStackViewを適用した場所は、次のようになりました。

004

4 各種の利用方法

それでは、UIStackViewが、各場所でどのように使用されたかを紹介します。

(1) 全体の構成は、比率を中心に定義

画面全体の構成は、次のようになっています。

005

まずは、上部の背景をタイマーViewとアニメーションViewの2つのビューで構成し、UIStackViewの中のViewを6対4の比率になるように制約を入れます。

続いて、このUIStackViewとその下のビュー全部を、更にUIStackViewで包み、最初のUIStackViewが、全体の0.6となるように制約を定義しています。

この辺は、背景となる画像を2つのViewに分割して適用する都合と、画像の縦横比を保つための作業です。

因みに、勇者がモンスターと戦っているアニメーションViewだけは、 SpriteKitSKViewとなっています。

また、その他のビューについては、一番下のADViewの高さを50と指定した以外は、同じように比率だけで定義しています。

このようにすることで、各種の画面サイズで、画像の縦横比や、必要なサイズを確保できるようになっています。 006

(2) Hiddenによる構成

UIStackViewでは、子ビューを複数持っている場合、その一部を表示したり非表示にしたりする事で、その他の子ビューの配置を自動的に調整してくれます。

今回、最終的に採用しなかったのですが、簡単にサンプルを書いてみると、次のようになります。

まずは、StoryboardUIButtonUILabelを配置し、それをUIStackViewで包んでおきます。

010

そして、テストボタンのアクションで、それぞれのhiddenを属性を切り替えています。

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var button: UIButton!

    @IBAction func tapTestButton(sender: AnyObject) {

        if button.hidden {
            label.hidden = true
            button.hidden = false
        } else {
            label.hidden = false
            button.hidden = true
        }
    }
}

実行結果は、次のようになります。

009

この機能を利用すると、状況によって表示される「武器強化ボタン」のようなものは、Hidden属性の切り替えるだけで、簡単に表現することができます。

007

008

なお、この要領については、下記においても詳しく解説されています。

[iOS 9] UIStackViewでAndroidのView.GONEを実装する

(3) 同一コントロールの連続配置

本アプリでは、獲得したトマトを表示するインジケータが画面の上部に配置されていますが、このようなものは、UIStackViewの最も得意とするものかも知れません。

011

UIStackViewには、Spacingというプロパティがあり、これを設置することで、全ての子コントロールの隙間を調整できます。

012

最終的に、バランスを調整する時など非常に簡単に修正できます。 これが、個々のコントロールの制約(左コントロールとの距離など)で定義されていたらと考えると本当に幸せになれます。

5 User Interaction Enabled

UIButtonには、画像・文字などを追加するプロパティがありますが、今回は、厳密なレイアウトを表現するために、UIImageUILabelを配置して表現する事になりました。

ボタンの上に画像やラベルを配置しても、あまり意識しなくてもボタンをタップすることができます。

014

画像やラベルの上をタップしても、ボタンのアクションが実行されます。(画像をクリックすると動作を確認できます)

013

しかし、この画像とラベルをUIStackViewで包んだ途端に、そこをタップしてもボタンを押せなくなってしまいます。

015

UIStackView上をタップしても、ボタンのアクションが反応しません。(画像をクリックすると動作を確認できます)

016

これは、UIStackViewがイベントを処理するため、その下に配置されているボタンにメッセージが届かないことによる問題です。 うっかりすると、UIStackViewの存在を忘れて、動作がおかしいなと思う事になるでしょう。

この問題は、UIStackViewでデフォルトでチェックされている User Interaction Enabled のチェックを外すことで解決できます。 ちょっと、注意が必要ですね。

017

6 最後に

今回は、実際にUIStackViewを使用した事例について紹介しました。

「本当にシンプルに画面設計ができてる!」というのが、使用してみた一番の感想です。

iOS9以降という制約が気にならなくなって、自由に利用出来る日が早く来ること願うばかりです。