iOS アプリの画面開発の基礎を理解する
前回の記事「iOS アプリの構造がどのようになっているか紐解いてみる」で iOS アプリの構造について説明しました。深いところの説明ばかりだったのでもう少し浅いところ、画面の見た目や画面遷移を実装する方法について説明します。
ユーザの要望がどのようにアプリに反映されるのか
アプリができる背景には「アプリでこんなことしたい」というユーザの要望とか、開発者自身の「アプリを通してXXのような素晴らしい体験をユーザに提供したい」という思いが出発点になっています。
ユーザの要望だったり開発者の思いは「UX設計」「ユースケース抽出」「UI設計」という3つの段階に分けてアプリに反映していきます。図にすると以下のような感じです。
- UX(ユーザエクスペリエンス)設計
ユーザの要望や開発者のこんなもの作りたいという思いを元に、いつ、どこで、誰が使うのか?アプリが使われる状況を洗い出す。その上でユーザがアプリを使うことによってどんな体験ができるのか、どんな印象を与えるのかをまとめる。 - ユースケース抽出
UX 設計を元にアプリに必要な機能(ユースケース)を列挙する。機能とは情報と処理をまとめたもの。 - UI(ユーザインターフェース)設計
抽出した機能をユーザの使い勝手と端末(iPhone または iPad)の特性に合わせてグループにまとめてどのように見せるか決める。
最終的にグループにまとまった機能を見せる単位が画面、分割された画面間の行き来が画面遷移として実現されます。
アプリ開発の3大要素
機能が洗い出されてある程度アプリの画面や画面遷移が決まると、次は機能をプログラムに落とし込んで実装していきます。開発者は実装すべき機能を「機能を見せる」「機能をつなげる」「機能を実現する」の3つのパートにわけてプログラムしていきます。図にすると以下のような感じです。
- 機能を見せる
ラベル、ボタン、テキスト入力など画面を構成するための部品(UI 部品またはビューと呼ぶ)とその組み合わせを実装する - 機能をつなげる
ビュー同士の動きの連携や画面遷移、まとまった機能をつなげるなどアプリの流れに関わる部分を実装する - 機能を実現する
情報を細かくデータ分割して処理とデータをまとめる。データの取得や保存、計算、ロジックなどを実装する
上記の3つのパートは Model-View-Controller(MVC)アーキテクチャ*1というソフトウェア構造のパターンと対応しています。
機能を見せる = View(ビュー) 機能をつなげる = Controller(コントローラ) 機能を実現する = Model(モデル)
iOS アプリの画面と画面遷移の実装は3大要素のどの部分と関係があるかというと「機能を見せる」と「機能をつなげる」になります。その役割を担うのが UIView と UIViewController クラスです。
残りの「機能を実現する」はデータ設計と関係があります。データ設計については以下の記事で説明していますのでそちらを参考にしてください。
iOS でどんなアプリを開発できるのか?
それでは iOS でどのようなアプリを開発することができるのか見てみましょう。iOS で開発することができるアプリは以下のように分類することができます。
- Single View Application
画面が1つだけのシンプルなアプリ - Utility Application
メイン画面と設定画面で構成されるアプリ - Master Detail Application
一覧画面と詳細画面で構成されるアプリ - Tabbed Application
タブを使って複数画面を切り替えるタイプのアプリ - Page-Based Application
ページめくりを使うアプリ - OpenGL Game
OpenGL を使ったゲーム。ゲームについては記事の範囲外になりますので詳細は割愛します。
アプリ開発をはじめるにあたって、開発者は上記アプリのうち1つを選んでベースにします。そのベースをもとに実現したい機能とマッチする画面と画面遷移を選択します。iOS アプリで使われる画面や画面遷移にもいくつかの種類があり、これらパターンを組み合わせてアプリを開発していきます。
以下は iOS アプリの代表的な画面と画面遷移の種類を分類したものです。
画面の種類
画面の情報をリスト形式で表示するかしないかで画面の種類が分かれます。
- リスト形式画面(Table View)
テーブルビューやコレクションビューを使ってリスト形式でデータを表示する画面 - ノーマルビューベース画面
テーブルビューやコレクションビューを使わない画面
画面遷移の種類
画面遷移と言えば一般的にはある画面から別の画面に移る(=遷移する)ことを画面遷移と呼びます。それだけだと少し分類しにくいので、画面遷移を大きくとらえて画面の上に別の画面を重ねて表示することや複数の画面を切り替えることも画面遷移としてカウントしてわけています。
- モーダル(Modal)
画面の上に新たに画面を重ねていく画面遷移方法。重ねられた(下位にある)画面は新たに開いた画面が閉じるまで操作できない。一番上に表示されているユーザが操作可能なビューのことをモーダルビューと呼ぶ - ポップオーバー(Popover)
画面の上に小さな画面を重ねて表示する。機能的にはモーダルと同じ。iPad で使用される - ナビゲーション(Navigation)
階層構造のあるデータを詳細画面に掘り下げていく画面遷移方法。ドリルダウンと呼ばれることもある。テーブルビューとセットで使用することが多い - スプリット(Split)
画面を2つの領域にわけて表示する。左側の項目を選択すると右側のページが切り替わる。iPad でナビゲーションの代わりに使用する。横向き(Landscape)と縦向き(Portrait)で表示が変わる。縦向きの時は右側の画面のみ表示され左側の画面はポップオーバーで表示する - タブ(Tab)
タブを使って画面を切り替える画面遷移方法 - ページめくり
電子書籍などページをめくって画面を移動する画面遷移方法
ここで列挙した以外の画面や画面遷移を持ったアプリを開発するには開発者が独自で UIView や UIViewController クラスを拡張する必要があります。
iOS アプリにおける画面とは
iOS において画面とは一体何か、どんな構造をしているか見ていきたいと思います。
iOS アプリの画面はユーザが実際目にするビューの集まりと、それらを制御する一つのビューコントローラで構成されています。iOS ではビューコントローラとビューを含めた一つの画面のことをシーン(Scene)と呼びます。
画面 = シーン = ビューの集まり + ビューコントローラ
iOS アプリでは複数のビューが重なり合って画面の見た目を構成しています。ビューの実態は UIView クラス(またはそのサブクラス)のオブジェクトです。また画面に配置されたビューはツリー構造になっていて、ビューコントローラが管理しています。ビューコントローラの実態は UIVIewController クラス(またはそのサブクラス)のオブジェクトです。
iOS アプリにおける画面遷移とは
iOS において画面遷移とは一体何か見ていきたいと思います。
iOS では、ユーザに見えているビューを管理するビューコントローラから別のビューコントローラに制御を移して別のビューを見せることで画面遷移を実現しています。ビューコントローラの遷移が画面遷移になります。iOS ではビューコントローラの遷移のことをセグエ(Segue)と呼びます。
画面遷移 = セグエ = ビューコントローラの遷移
これ以降、アプリの画面説明では単に画面遷移と表現しますが、プログラム説明の時にはビューコントローラの遷移またはセグエという表現を使います。
iOS アプリの画面と画面遷移の作成方法
iOS アプリの画面と画面遷移を作成するには Xcode に付属しているストリボードと呼ばれるツールを使います。
ストリーボードを使うとビューの配置やビューコントローラの遷移(セグエ)をプログラムを書かずビジュアルに作成することができます。では実際にストーリーボードを使って画面デザインをする方法をみてみましょう。
以下の簡単なアプリを例に画面と画面遷移を作成していきます。
画面いっぱいに表示した UIView オブジェクトの上に適当な大きさの UIView オブジェクトを重ねてさらにその上に UILabel オブジェクトと UIButton オブジェクトを配置しています。
プロジェクトの作成
まずはじめにプロジェクトを作成します。Xcode の「File」メニューから「New」、「New Project...」の順に選択してください。
次に「Single View Application」を選択して「Next」ボタンを押してください。
「Use Storyboard」と「Use Automatic Reference Counting」にチェックが入っていることを確認して「Product Name」と「Company Identifer」を入力後「Next」ボタンを押してください。名前は適当でかまいません。
最後にプロジェクトの保存場所を指定して「Create」ボタンを押してください。
画面(シーン)にビューを配置する
アプリの画面(シーン)にビューを配置していく方法を見ていきましょう。
Xcode からプロジェクトの .storyboard 拡張子のついたファイルをクリックしてストリーボードを開きます。ファイルを開くと右矢印で示されたステータスバー付きのアプリの画面(シーン)が一つ表示されます。
以下のように、右下にある Objects 欄の「View」をマウスで選択してシーンの上にドラッグします*2。
同じ要領で Label や Round Rect Button など画面に配置したい UI 部品を選んでドラッグします。
サンプルの例では View, Label, Round Rect Button を配置しています。
ビューコントローラの遷移を追加する
Objects 欄の「View Controller」をマウスで選択して方眼紙の領域にドラッグしてください。
元々あった画面のボタンをマウスで選択して「control」ボタンを押しながら新しく追加した画面にドラッグします。
マウスを離すと小さなポップアップが表示されますのでそこから「Modal」を選択してください。
以上でビューの配置とビューコントローラの遷移が定義できました。アプリを起動するとボタンがラベルとボタンが表示されボタンを押すと画面が遷移します。
遷移先画面から元の画面に戻る処理を追加する
ここからはストリーボードの設定に加えて少しだけプログラムを書く必要があります。
まずはじめに UIViewController クラスを継承した新たなクラスをプロジェクトに追加します。クラス名は ModelViewController とします。
次にストーリーボードを開いて新たに追加した画面の下部にある「Modal View Controller」アイコンを選択します。
下記のように、右側のCustom Class グループの Class 項目を UIViewController から ModalViewController に変更します。
次に以下のように ModalViewController クラスにボタンがクリックされた時の処理を追加します。
@interface ModalViewController : UIViewController // ボタンが押された時に呼ばれるメソッド - (IBAction)respondToButtonClick:(id)sender; @end @implementation ModalViewController - (IBAction)respondToButtonClick:(id)sender { // 画面を閉じる処理 [self dismissViewControllerAnimated:YES completion:nil]; } @end
respondToButtonClick: メソッドの戻り値の IBAction はストリーボードのボタンオブジェクトとプログラムをつなぐために必要な設定です。実際は void と同じです。ちなみに IB は Interface Builder の略です。
最後にストーリーボードのボタンとプログラムを接続します。Xcode のメニューから「View」「Assistant Editor」「Show Assistant Editor」の順に選択して Assistant Editor を開きます。Assistant Editor を開くと右側にプログラムが表示されます。その後、以下のように Modal View Controller のボタンオブジェクトを選択して「control」を押しながらマウスでメソッドの定義までドラッグします。
以上で新たに表示した画面を閉じる処理の定義ができました。
UIView クラス
UIView は画面で表示するあらゆる UI 部品系クラスの親クラスです。UIView クラスは画面に矩形を表示する機能とビューのツリー構造を管理する機能を提供してくれます。
矩形を表示する機能
画面上に長方形のエリアを表示する機能です。長方形のサイズと背景色を設定することが出来ます。
ビューの種類
iOS ではボタンやラベルなど UIView を拡張したクラスが多数提供されています。
以下は UIView クラスを継承したクラスの関係を表した図です。
上記図には iOS で提供されている UIView のサブクラスすべて含まれています。すべてのクラスをリストアップしてみます。
表示系
文字や画像などデータを表示する
- UILabel
文字を表示する為に必要な機能を提供してくれるクラス - UIImageView
画像を表示する為に必要な機能を提供してくれるクラス
コントロール系
ユーザがタッチしてデータを入力またはデータを選択する
- UIControl
ユーザインタラクションのために必要な基本機能を提供してくれるクラス。このクラスをそのまま使用するのではなく継承して使う - UIButton
ボタンの機能を提供してくれるクラス - UISwitch
オンオフスイッチの機能を提供してくれるクラス - UISlider
スライダーの機能を提供してくれるクラス。スライダとは連続した値の中から1つの値を視覚的に選択するためのコントロール - UIStepper
ステッパーの機能を提供してくれるクラス。ステッパーとは「+」と「-」ボタンを使って入力する値を段階的に入力できるコントロール - UIPageControl
ページ選択機能を提供してくれるクラス - UISegmentedControl
トグルボタンの機能を提供してくれるクラス。トグルボタンとは複数の値の中から1つの値を選択するためのコントロール。選択する値の数は2〜3個が最適 - UITextField
テキスト入力の機能を提供してくれるクラス - UIRefreshControl(iOS 6追加)
リフレッシュコントロールの機能を提供してくれるクラス。リフレッシュコントロールとはメールや Twitter アプリの「引っ張って更新」の見た目を表現するコントロール
ピッカー系
ピッカー形式でデータ表示する
- UIPickerView
ピッカーの機能を提供するクラス。ピッカーとは複数の値の中から1つの値を選択するためのコントロール。選択する数は3個以上が最適 - UIDatePicker
日付を選択するための機能を提供してくれるクラス
バー系
画面の上部や下部に表示するバー
- UINavigationBar
ナビゲーションバーを表示するための機能を提供してくれるクラス。 - UIToolbar
ツールバーを表示するための機能を提供してくれるクラス。 - UITabBar
タブバーを表示するための機能を提供してくれるクラス。 - UISearchBar
検索バーを表示するための機能を提供してくれるクラス。
ユーザ待機系
ユーザに処理中であることを通知する
- UIProgressView
アプリが何らかの処理をしていることをユーザに知らせる機能を提供してくれるクラス - UIActivityIndicatorView
処理の進行状況を表示するための機能を提供してくれるクラス
ユーザ対話系
ユーザにアクションを提案して次の行動をうながす
- UIActionSheet
アクションシートのための機能を提供してくれるクラス - UIAlertView
ユーザに警告を表示する機能を提供してくれるクラス
スクロール系
画面サイズより大きなビューをスクロールして表示する
- UIScrollView
画面スクロールに必要な機能を提供してくれるクラス - UITextView
大量のテキストを入力する機能を提供してくれるクラス - UIWebView
Web ページを表示する機能を提供してくれるクラス
リスト系
リスト形式でデータを表示する
ビューの追加方法
画面にビューを追加する方法は2つあります。一つは先ほど紹介したストーリーボードを使う方法、もう一つはプログラムで追加する方法です。ここではプログラム上でビューを追加する方法を説明します。
プログラム上でビューを追加するにはまず UIViewController クラスのサブクラスを作成してそのクラスの viewDidLoad メソッドにビュー追加のプログラムを書いていきます。
以下はその例です。
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; /* * ここにビューを追加するプログラムを書く */ } @end
次にビューをインスタンス化します。UIView クラスにはビュー初期化用の initWithFrame: メソッドが用意されていますのでそのメソッドを使ってインスタンス化します。initWithFrame: メソッドは CGRect 構造体のインスタンスを引数にとります。
以下は initWithFrame メソッドを使ってオブジェクトを生成する例です。
// xy 座標 (0, 0)、幅100、高さ100の UIView クラスのインスタンスを生成する UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
最後に表示するビューを追加します。ビューコントローラは自身の管理するビューを view プロパティとして持っています。この view プロパティにサブビューを追加します。
サブビューの追加には UIView クラスの addSubview: メソッドを使います。このメソッドは UIView オブジェクトを引数にとり、引数の UIView オブジェクトをビュー階層に追加します。
以下は UIView クラスのオブジェクトを生成後、背景色をセットしてビューを追加するプログラムの例です。
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; // UIView オブジェクトの背景色のデフォルト値は透明なため背景色を別の色に設定 view.backgroundColor = [UIColor redColor]; [self.view addSubview:view]; } @end
UIViewController クラス
UIViewController クラスは iOS アプリの画面と紐づいて画面や画面遷移を管理するクラスです。iOS アプリには必ず画面が一つ以上存在しているためアプリ開発者は UIViewController クラスを必ず使用しなければなりません。UIViewController は iOS アプリ開発の中心となるクラスです。
UIViewController クラスが提供する機能は大きくわけると2つあります。1つは画面に表示しているビューを管理する機能、もう1つは他のビューコントローラに遷移させる機能です。
ビューを管理する機能
UIViewController オブジェクトはビューの階層の一番上位の UIView オブジェクトを view プロパティとして保持して、画面に表示するビューを管理しています。図にすると以下のようになります。
また UIViewController クラスにはビューが生成されるタイミングやビューが表示されるタイミングで呼び出されるイベントメソッドが定義されています。またメモリワーニング時にビューが破棄されるタイミングで呼び出されるメソッドなども定義されています。これらのイベントメソッドをオーバーライドしてビューのライフサイクルを監視することができます。
UIViewController のライフサイクルイベントについての詳細は以下の記事を参考にしてください。
他のビューコントローラに遷移させる機能
UIViewController オブジェクトはユーザアクションに応じてストリーボードに定義されているセグエ(Segue)を参照して別のビューコントローラに制御を移します。
セグエにはモーダル(Model)、プッシュ(Push)、カスタム(Custom)の3種類あります。UIViewController クラスはモーダルで画面遷移する機能を提供します。モーダルセグエには Cover Vertical や Flip Horizontal など4種類のアニメーションを設定することが出来ます。
ビューコントローラの種類
iOS には UIViewController クラスを拡張した便利なクラスが存在します。これらのクラスを使用すると、より複雑な画面管理や画面遷移を簡単に作成できます。ビューコントローラは画面表示を支援するものと画面遷移を支援するものにわけることができます。
以下は UIViewController クラスを継承したクラスの関係を表した図です。
それでは上記図のクラスをリストアップしてみます。
画面表示支援系
- UITableViewController
テーブルビューを表示するための機能を提供するクラス。UITableView と組み合わせて使う - UICollectionViewController
コレクションビューを表示するための機能を提供するクラス。UICollectionView と組み合わせて使う
画面遷移支援系
- UINavigationController
ナビゲーションを使った画面遷移の機能を提供するクラス - UISplitViewController
スプリットを使った画面遷移の機能を提供するクラス - UITabBarController
タブを使ったを使った画面遷移の機能を提供するクラス - UIPageViewController
ページめくりを使った画面遷移の機能を提供するクラス
UIViewController と UITableViewController、UICollectionViewController クラスはアプリ開発者がクラスを継承して使用します。他のクラスは直接使用します。
図に表すと以下のようになります。
画面表示支援系ビューコントローラは開発者が継承して使う、画面遷移支援系ビューコントローラは直接使うと覚えるとわかりやすいと思います。
また画面遷移支援系ビューコントローラは複数のビューコントローラをまとめて管理するのでコンテナビューコントローラと呼ばれることがあります。
画面を追加して遷移させる方法
ここではストーリーボードを使わずにプログラム上で画面を追加してそこに遷移させる方法について説明します。プログラムは「ビューの追加方法」で使った ViewController クラスをベースにプログラムを追加していきます。
はじめに ViewController クラスの viewDidLoad メソッドにボタンを追加する処理とボタンが押された時に呼ばれるメソッドを追加します。
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; : : ビューの追加処理は省略 : // ボタンオブジェクトを生成する UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // ボタンの大きさ表示させる場所を指定する button.frame = CGRectMake(0, 0, 100, 44); // ボタンに表示させる文字列の設定 [button setTitle:@"button" forState:UIControlStateNormal]; // ボタンが押された時に呼び出されるメソッドの設定 [button addTarget:self action:@selector(respondToButtonClick:) forControlEvents:UIControlEventTouchUpInside]; // ボタンをビュー階層に追加 [self.view addSubview:button]; } - (void)respondToButtonClick:(id)sender { // ビューコントローラ遷移の処理を書く } @end
UIButton クラス(正確には親クラスの UIControl のメソッドです)の addTarget: action: forControlEvents: はボタンが押された時にどのオブジェクトのどのメソッドを呼び出すか設定することが出来るメソッドです。ボタン押下などユーザアクションが発生した時に処理を別のオブジェクトのメソッドに依頼する方法をターゲットアクションパターンと呼びます。
次に遷移先ビューコントローラをインポートします。
#import "ViewController.h" #import "ModalViewController.h" @implementation ViewController : : 省略 : @end
最後にボタンが押された時の処理を追加します。
@implementation ViewController : : 省略 : - (void)respondToButtonClick:(id)sender { // ビューコントローラオブジェクトを生成する ModalViewController *controller = [[ModalViewController alloc] init]; // 背景色を白に設定する controller.view.backgroundColor = [UIColor whiteColor]; // ビューコントローラをモーダルで遷移させる [self presentViewController:controller animated:YES completion:nil]; } @end
以上でビューコントローラに遷移させることができます。遷移先画面から戻る処理については、ストーリーボードを使う時と同じなので省略します。
UIView と UIViewController の組み合わせ例
UIView(またはそのサブクラスの)オブジェクトと UIViewController(またはそのサブクラスの)オブジェクトの組み合わせを考えてみたいと思います。以下に UIView と UIViewController の組み合わせ例を示します。図中の青色のオブジェクトがビューコントローラになります。
Single View Application
ノーマルビューベース画面を表示するだけのシンプルなアプリです。画面遷移はありません。
Master Detail Application
テーブルビューと使用した画面とノーマルビューベース画面をナビゲーションで画面遷移させます。iPhone と iPad で使うオブジェクトが変わります。iPad の場合はスプリットを使って画面遷移します。
Tabbed Application
ノーマルビューベース画面をいくつか用意してタブで画面遷移させます。タブの中に Master Detail Application をネストすることもできます。
Page-Based Application
ノーマルビューベース画面をページめくりで画面遷移させます。図中の ModelController オブジェクトは画面に表示させるデータを管理するために使う特別なコントローラオブジェクトです。
UIView と UIViewController クラスの共通の機能
UIView と UIViewController クラスの共通の機能としてユーザアクションイベントを処理する機能があります。この機能は UIResponder クラス が提供している機能です。UIView と UIViewController クラスはともに UIResponder クラスを継承しているのでユーザアクションイベントを処理することができます。
ユーザアクションイベントの詳細は下記の記事を参照してください。
まとめ
- iOS アプリには5種類あってそれを構成する画面と画面遷移のパターンは画面が2種類、画面遷移が6種類あります。
- 画面と画面遷移はプログラムで作成することもできますが、ストーリーボードを使うとプログラム記述量を減らしてビュジュアルに作成することができます。
- ストーリーボードは画面(シーン)と画面遷移(セグエ)を定義することが出来ます。シーンはビューとビューコントローラで構成されるアプリの画面のことでセグエはビューコントローラが遷移して画面が切り替わることをさします。
- UIView は矩形領域を表示する機能を持ったクラスで UIView をベースに様々な UI 部品用クラスが存在します。この UIView およびそのサブクラスを使って画面を構築することができます。
- UIViewController はビューのライフサイクルの管理と画面遷移の機能を持ったクラスです。UIViewController をベースにしたクラスがあり複雑な画面管理や画面遷移をする機能を持っています。
ブログの記事が本になりました!
A Day In The Life の iOS に関する記事が書籍になりました。この記事の内容は書籍で読むことができます(2015年1月17日にSwiftに対応した改訂版がでました)。