2014年10月21日火曜日

UI部品の生成を関数として用意する

設計方針で、Interface Builderもstoryboardも使わないと決めました。大きな理由の1つに、変更に対する柔軟性の確保があります。その実現には、UI部品を生成するための共通処理が必要です。

 

swiftの場合、具体的にはどうするのでしょう。考え方としては、どのUI部品でも、部品を使う側のソースコード上ではなく、別に用意した処理を通して生成することにします。swiftなら、関数が最適でしょう。UIButtonを生成する関数、UILabelを生成する関数など、部品の種類ごとに用意します。具体的にな例としては、つぎのようなコードになります。

func createLabelF(text: String, text_size: CGFloat, align: NSTextAlignment, 
        x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) -> UILabel {
    let iLabel: UILabel = UILabel(frame: CGRectMake(x, y, width, height))
    iLabel.backgroundColor = UIColor.clearColor()
    iLabel.text = text
    iLabel.font = UIFont(name: FONT_NAME_DEFAULT, size: text_size)
    iLabel.textColor = UIColor.blackColor()
    iLabel.textAlignment = align
    return iLabel
}
//(注:ここで「FONT_NAME_DEFAULT」は、別に定義した値です)

こうした関数で重要なのは、UI部品ごとのデフォルト設定を入れておくことです。デフォルト設定とは、一番使う設定のことです。決まった設定を全部入れておくことで、生成後に細かく設定する必要がなくなります。逆に、よく設定する項目は、引数に入れておきます。引数に入れておくことで、関数を呼び出した後、別に設定する必要がなくなります。

 

使い方は簡単です。たった1行だけで、UI部品を生成できます。次のように書くだけです。

let labelTitle = createLabelF("日付", 18, ALIGN_LEFT, 690, 320, 45, 25)
//(注:ここで「ALIGN_LEFT」は、別に定義した値です)

もしデフォルトと違う設定で作る場合も簡単です。生成したインスタンスに、必要な変更を加えるだけです。具体的な例は、次のようになります。

let labelTitle = createLabelF("日付", 18, ALIGN_LEFT, 690, 320, 45, 25)
labelTitle.layer.borderWidth = 1
//(注:ここで「ALIGN_LEFT」は、別に定義した値です)

このソースコードには、別な意味も含まれています。このラベルは、デフォルトのラベルとは違う設定で、borderWidthだけが変更されいていると分かるのです。

こうした関数を使わないで作る場合を考えてみてください。全部のソースコードに、ラベル生成をベタで書いた場合です。同じようなソースコードが各所に並んでるだけでなく、どれがデフォルトの設定か、またはデフォルトとはどこが違うのか、ソースコードから読み取るのは非常に困難です。共通の生成関数を作ることは、デフォルトを統一するだけでなく、デフォルトと何が違うのかまで明確にしてくれます。これも大きなメリットです。

 

UI部品ごとの生成関数は、いろいろな場面で使うはずです。ですから、どこからでも呼び出せる形にします。具体的には、1つのswiftソースファイルに集めて、プロジェクトに1個だけ用意します。私の場合は、ファイル名を「zz_base.swift」としてます。ファイル名の最初の3文字が、ソースファイルの分類となります。「zz_」は、プロジェクトで共通につかう機能を意味し、基本となる部品なので「base」としました。

このファイルは、関数を並べただけですから、どのswiftソースファイルからも関数名だけで呼び出せます。そうでないと使いにくいですから、わざとそうしているというわけです。

 

また、この一連の関数は、UI部品を使うアプリなら必ず入れます。1個用意しておくだけで、すべてのアプリで使えるというわけです。一度用意しておけば、ほぼすべてのアプリで共通に使えます。アプリのプロジェクトを生成したら、真っ先に入れるソースファイルとなります。アプリ共通で使えるライブラリと呼んでも良いでしょう。

 

ここからは応用の話です。UI部品ごとに1つの関数を用意するのは基本ですが、絶対に1つとは限りません。ボタンのデザインが2種類必要で、それぞれに別な役割や使いどころがあるとしたら、生成関数を2つ用意するのがベストです。それぞれ別々にデフォルト値を持ち、デフォルト値を変更してもお互いに干渉しません。分けた関数ごとに、デフォルトの変更は簡単ですし、それぞれ独立してデフォルトを変えられるのもメリットとなります。

また、別な拡張の仕方も容易になります。たとえば、特定の種類のボタンには、タップ中に別な表示や動きやをさせるといった場合です。UIButtonのサブクラスを作って、そこに表示や動きを記述します。該当する種類のボタン生成関数では、UIButtonの代わりにサブクラスのボタンを生成し、UIButtonボタンとして返します。このような方法なら、後からでもボタンの機能を容易に追加できます。変更するのは、サブクラスの追加と、ボタン生成関数だけです。ボタン生成を呼び出している側のソースコードを変更する必要はありません。もちろん、呼び出し側をまったく変更せず実現できる機能は限定されますが、変更への柔軟性が高いことは確かです。

 

以上のように、UI部品は必ず関数で生成するように作ると、変更への柔軟性は格段に高まります。また、一度作っておけば、どのアプリにも使い回しできて非常に便利です。UI部品の関数に限らず、このような複数アプリで共通で使えるライブラリが充実すると、まったく新規のアプリ開発でも、最初から3割ぐらい出来上がった状態で始めるのと同じです。

0 件のコメント:

コメントを投稿