オフスクリーン描画機能をライブラリ化する話の続きです。ライブラリ用のクラスを作り終わったので、今度は使ってみる段階です。どのように使うと良いのかも含めて、使用例を紹介します。
まず最初に、一番大事な点を。ライブラリ化した描画機能を使うのですが、何を描いているのか、どのように描いているのか、ソースコードを見て理解しやすいことが大切です。そのためには、ライブラリを使う側でも工夫が必要です。
その工夫とは、まず登録する色に名前をつけることです。一番良いのは、色の役割で名前を付けることですが、それが難しい場合には、色そのものの名前(BlueやRedなど)でも構いません。描画メソッドを呼ぶ際に、色の名前をつけることで、どんな色で描かれるのか把握しやすくなります。
さらには、描画する内容を整理して見せることです。描く全体像をグループ分けして、グループごとにコメントを付けて区切るだけでも、それぞれが何を描いているか理解しやすくなります。一般的には、描画する領域を数個に分け、それぞれの間にコメント行を挿入して理解しやすく仕上げます。
もう1つ、描くものが大きくて要素の数が多い場合には、描画領域を区分けして、区分け領域の相対位置で座標を指定するようにします。複数のUIViewを使って、表示画面を区分けするのと同じような考えです。具体的には、領域ごとの座標点を持つ変数(それぞれにXとYで2つずつ)を用意し、メソッド中の座標指定では、用意した変数と数値との加算式を用います。なお、これが必要になるケースは少ないと思いますから、この具体例は今回省きます。
主な工夫は、以上です。たったこれだけの工夫でも、描いている内容が大まかに見通せるようになります。
最初に用意するのは、色の変数です。使う色の数だけ、変数を用意します。具体的なSwiftコードを見たほうが理解しやすいでしょう。次のように作ります。
// 描画を開始(インスタンス生成)
var iDraw = DrawImageOffScreen(400, 150, false, 10)
// 色ごとに変数を用意する
let cMain : Int = 0 // 組織のメインカラー
let cMainL : Int = 1 // 組織のメインカラー(薄)
let cTextDark : Int = 2
let cTextLight : Int = 3
let cTextSp : Int = 4 // 注目させる色
let cLineStrong : Int = 5
let cLineWeak : Int = 6
let cDecoLine : Int = 7
let cDecoBox : Int = 8
let cDecoCircle : Int = 9
色の変数を宣言する前に、クラスのインスタンスを生成しています。その理由は、描く処理をここから開始するという宣言の意味を込めているからです。インスタンス生成後に変数が来ると、これらの変数が、このインスタンスで使われると理解しやすくなりますので。
変数の名前は、すべて小文字のcで始まっています。colorを意味するcで、colorだと長いため、1文字のcを採用しました。
同様に、cに続く名前も、あまり長く付けないように心がけます。DecorationもDecoと省略して、最低限の長さにしています。できるだけ短い名前にすると、名前を使う側のソースコードも短くなり、少しですが読みやすさが増します。もし名前の意味を細く説明したい場合は、コメントとして追加すれば良いでしょう。
この例では、描く要素の役割ごとに名前をつけています。たとえ同じ色でも、役割ごとに名前を用意し、別々に使うことが重要です。後で色を変更したときに、役割の違う色まで一緒に変わるという問題が発生しません。このブログの間接参照のときに説明した、変更への柔軟性を高める作り方です。
続いて、色の値を設定します。もう名前が付いているので、名前順に一気に並べて、設定メソッドを呼び出すだけです。具体的なSwiftコードは次のようになります。
// 色に値を設定する
iDraw.setContextStrokeColorF(cMain, 0.1, 0.1, 1.0, 1.0) // 純粋ではない濃い青
iDraw.setContextFillColorF(cMain, 0.9, 0.9, 1.0, 1.0) // 薄い青
iDraw.setContextStrokeColorF(cTextDark, 0.1, 0.1, 0.1, 1.0)
iDraw.setContextStrokeColorF(cTextLight, 0.5, 0.5, 0.5, 1.0)
iDraw.setContextStrokeColorF(cTextSp, 1.0, 0.0, 0.0, 1.0) // 注目色:赤
iDraw.setContextStrokeColorF(cLineStrong, 0.1, 0.1, 1.0, 1.0)
iDraw.setContextStrokeColorF(cLineWeak, 0.7, 0.7, 1.0, 1.0)
iDraw.setContextStrokeColorF(cDecoLine, 0.1, 0.1, 1.0, 1.0)
iDraw.setContextFillColorF(cDecoBox, 0.1, 0.1, 1.0, 0.5)
iDraw.setContextFillColorF(cDecoCircle, 0.3, 1.0, 0.3, 0.5)
どの色も、デフォルトの値を持ってますから、変更が必要な値のみを設定するだけです。また、使わない値を設定する必要もありません。線色(StrokeColor)だけ、塗りつぶし色(FillColor)だけというのもアリです。もちろん、使わないけど念のために設定しておくのもアリです。
ここでも、何か細くしたいことがあれば、コメントとして追加します。光の3原色(RGB)の仕組みが分かっていれば、3つの数値を見ただけで大まかな色は理解できますが、そうでない人のためにコメントで補足するのは、良い心遣いといえますね。
知人が話してくれたのですが、使わない色にも必ず設定するというのもアリだそうです。使わない色の全部に、そのアプリでは絶対に使わない目立つ色(たとえば紫とか)を設定しておきます。もしそれが表示さたら、指定の間違いを発見できるという使い方です。このようなエラー発見方法もありますという紹介でした。面倒なので、私は使っていませんが。もし採用する場合は、コメントで「使ってない色」と付けておくべきでしょう。
色の登録が終わったので、いよいよ描く段階です。描く領域で区分けして、間にコメント行を入れながら、通常は上から順番に描きます。最後に、描いた結果を変数に入れるか、UIImageViewのimageプロパティに設定します。具体的なSwiftコードですが、以下のコードは架空の整理券を描いています。
// ここから描画命令
// 整理券情報
iDraw.drawRectF(cMain, .Both, 1.0, 10.0, 10.0, 170.0, 60.0)
iDraw.drawTextF(cTextDark, "整理番号:", 16.0, 15.0, 13.0)
iDraw.drawTextF(cTextDark, iNumTicket, 30.0, 15.0, 33.0)
for i in 0...24 {
var iX : CGFloat = 190.0 + (8.0 * CGFloat(i))
iDraw.drawLineF(cDecoLine, 1.0, iX, 30, (iX + 10.0), 10.0) // 飾り
}
// タイトルと日付
iDraw.drawTextF(cTextDark, "入場整理券", 16.0, 200.0, 35.0)
iDraw.drawTextF(cTextDark, " 日付:2014年12月20日", 14.0, 200.0, 55.0)
// 中央の区切り線
iDraw.drawLineF(cLineStrong, 3.0, 10.0, 80.0, 380.0, 80.0)
for i in 0...23 {
var iX : CGFloat = 20.0 + (15.0 * CGFloat(i))
iDraw.drawCircleF(cDecoCircle, .Fill, 1.0, iX, 75, 10.0, 10.0) // 飾り
}
// 会員情報
iDraw.drawTextF(cTextDark, ("会員番号:" + iNumMember), 14.0, 15.0, 90.0)
iDraw.drawTextF(cTextSp, "開催場所:秘密(招待メール参照)", 14.0, 180.0, 90.0)
// 発行人
iDraw.drawTextF(cTextLight, "発行人:ガイガー・カウント・グループ", 12.0, 180.0, 115.0)
iDraw.drawTextF(cTextLight, "watashida@gaigaigai.com", 12.0, 250.0, 130.0)
for i in 0...17 {
var iX : CGFloat = 10.0 + (8.0 * CGFloat(i))
iDraw.drawLineF(cDecoLine, 1.0, iX, 140, (iX + 10.0), 120.0) // 飾り
}
for i in 0...7 {
var iX : CGFloat = 165.0 + (10.0 * CGFloat(i))
iDraw.drawRectF(cDecoBox, .Fill, 1.0, iX, 134, 8.0, 8.0) // 飾り
}
// UIImageをImageViewに保存
iImageView.image = iDraw.getFinalImageF()
このブログ上の表示では、区切りのコメント行も同じ色なので見づらいですが、Xcodeのエディタ上ではコメント行が薄い色になり、区切りが明確に見えます。
同じ領域の描画要素を並べるので、位置関係が把握しやすくなっています。座標の数値を変更して、重ならないように移動したり、逆に重ねたりも容易でしょう。
色に名前をつけたので、どんな役割の色が割り当てられているのかも、簡単に読み取れます。引数には変数も含まれていますが、描かれている内容は大まかに想像できます。あとは実際に表示や印刷してみて、座標の値を細かく調整するだけです。
上記の例では、飾りを描画するfor文が何個もあるので、全体として見づらくなっています。試しに、for文だけ削除してみましょう。
// ここから描画命令
// 整理券情報
iDraw.drawRectF(cMain, .Both, 1.0, 10.0, 10.0, 170.0, 60.0)
iDraw.drawTextF(cTextDark, "整理番号:", 16.0, 15.0, 13.0)
iDraw.drawTextF(cTextDark, iNumTicket, 30.0, 15.0, 33.0)
// タイトルと日付
iDraw.drawTextF(cTextDark, "入場整理券", 16.0, 200.0, 35.0)
iDraw.drawTextF(cTextDark, " 日付:2014年12月20日", 14.0, 200.0, 55.0)
// 中央の区切り線
iDraw.drawLineF(cLineStrong, 3.0, 10.0, 80.0, 380.0, 80.0)
// 会員情報
iDraw.drawTextF(cTextDark, ("会員番号:" + iNumMember), 14.0, 15.0, 90.0)
iDraw.drawTextF(cTextSp, "開催場所:秘密(招待メール参照)", 14.0, 180.0, 90.0)
// 発行人
iDraw.drawTextF(cTextLight, "発行人:ガイガー・カウント・グループ", 12.0, 180.0, 115.0)
iDraw.drawTextF(cTextLight, "watashida@gaigaigai.com", 12.0, 250.0, 130.0)
// UIImageをImageViewに保存
iImageView.image = iDraw.getFinalImageF()
文字列の描画が中心ですが、かなり見やすくなり、処理内容が読み取りやすくなったと思います。この状態が、今回のクラスを使う際に狙っていた形です。
今回の描画ライブラリでは、1つの要素を描くのに、必ず短い1行で書き終えることを重視しています。それぞれの行では、メソッド名で描く要素の種類を、色の名前で色の役割を、それ以降の引数で文字列や座標や大きさを読み取れます。複数行のメソッドが並んでも、楽に読み取れると思います。
描画ライブラリを使う側の作り方は、以上です。ここまで、swiftソースコードを分割して取り上げましたが、3つを単純に並べたものが、実際のソースコードになります。その並べた様子も、同じく整理された状態に見えます。
ここまで紹介した使い方の構成を簡単に整理すると、次のようになります。
ライブラリを使う側の全体構成
・色の変数名を用意
・色の値を設定して登録
・色を使って描く(描く内容を領域で分割:間にコメント行)
この構成に合わせて作れば、読みやすくて修正しやすいソースコードになると思います。
ここで挙げた例は、座標や文字列を直接入れたものが中心でした。しかし、私が作成した某業務アプリでは、印刷レイアウトをiPad上で編集する機能を付けました。印刷のレイアウトなどは、細かな変更依頼が何度も発生すると考え、レイアウトの編集機能もiPad上で作ってしまいました。その際には、すべての引数の値を変数に入れ、描画メソッドを呼び出す形となります。
レイアウト機能と連動させても、このライブラリは問題なく動きます。でも、ほぼ自由にレイアウトできるため、ソースコードから印刷内容を読み取ることが、まったく関係なくなります。使う側のソースコードの読みやすさは、描画内容をベタで書いたときの読みやすさを重視すべきなのでしょう。ここで取り上げた例のように。
今回は、作成した描画ライブラリの使用例を紹介しました。これで一通りの解説は終わったのですが、まだ宿題が残っています。CGContextを使った描画での特徴を理解できるような、ライブラリの使用例です。次回は、それを取り上げる予定です。
(使用開発ツール:Xcode 6.0.1, SDK iOS 8.0)
0 件のコメント:
コメントを投稿