![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ![]() | ||
![]() | ![]() | ![]() | ![]() | ![]() |
|
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
以下は、Mac OS X 10.5.1 上の Xcode 3.0 で説明しています。
| 1 README.rtf の日本語訳 2 アプリケーション 3 ファイル構成 4 MainMenu.nib 5 SimpleLayoutView クラス |
5.1 継承とインスタンス変数 5.2 初期化 5.3 ボックスの追加と除去 5.4 配置の再計算とアニメーション 6 まとめ |
AnimatingViews は、以下のための NSView の非常に単純なサブクラスを実演する小さなアプリケーションです。
SimpleLayoutView.m は、サブクラスを実装します。
ビュー自体は、描画を何も行いません(したがって、オーバーライドされた drawRect: を持っていません)。その内容は、単にそれに追加された下位ビューです。このデモでは、単に色付きのボックスを追加しますが、どんな種類のビューでも追加できます。
現在のところ、選択された配置スタイルは、layoutStyle プロパティとして保存されています。layout メソッドは、レイアウトを再計算し、下位ビューのフレームを新しい位置へと変更します。ビューではなく、[view animator] 上でフレームを設定することで、サフビューは新しい位置へ非同期でアニメーションされます。
ビューは、他の多くの状態変更に対して、自動的に再配置されないことに注意してください。したがって、下位ビューを追加・除去するアクションも、明示的な配置を起こすために layout を呼び出します。
このサンプルは、Leopard で追加された API を使って色付きの NSBox インスタンスを作成する方法も実演します。
まず、Xcode 上でビルドして実行してみます。アプリケーションを起動すると、次のようなウインドウが表示されます。
![]() |
真ん中のビューに正方形が表示されていますが、起動時は何も表示されていません。右下の「Add(追加)」をクリックすると NSBox である正方形が追加され、「Remove(除去)」をクリックすると最後に追加された正方形が除去されます。また、左下のマトリックス(ラジオボタン)は、左から「Grid(グリッド)」、「Row(行)」、「Column(列)」となっていて、これを選択すると、選択した形で正方形が並べ替えられます。また、下の真ん中右のカラーウェルは、色の組を指定するもので、これを指定した後で正方形を追加すると、色の違う正方形が追加されます。上の図では、緑色に変更した後でひとつ追加した後の状態を示しています。配置方法は「Column」です。
プロジェクトを構成しているファイルは、以下のようになっています。
![]() |
独自ファイルは、SimpleLayoutView.h と .m です。あと MainMenu.nib にユーザーインターフェイスの設定があります。あとは通常のアプリケーションと変わりません。
MainMenu.nib は次のようになっています。
![]() |
File's Owner、Application などの委任などの設定はなにもありません。ウインドウ内には SimpleLayoutView クラスのインスタンスがあります。このインスタンスのアウトレットは boxColorField で、これが真ん中下のカラーウェルに接続されています。また、左下のマトリックスからは changLayout:(レイアウトを変更する)、右下の「Add」ボタンから addABox:、右下の「Remove」ボタンから removeLastBox: というアクションメソッドが、ターゲットを SimpleLayoutView にして接続されています。
SimpleLayoutView クラス唯一の独自クラスである SimpleLayoutView を見ていきましょう。SimpleLayoutView.h におけるインターフェイス宣言は以下のようになっています。
最初のものは配置スタイルを保持するものです。これは、左下のマトリックスに対応しています。Layout 型はこれより前で定義されていて、次のようになっています。
boxColorField は、nib ファイルで接続されていたアウトレットで、真ん中下のカラーウェルを参照します。
nib ファイルで委任などが接続されていなかったので、このサンプルでは起動したとき、nib が読み込まれ、ウインドウが表示されるだけです。あとはユーザーがボタンをクリックするなど、何らかの行動を起こさないかぎりそのままです。
nib ファイルが読み込まれるとき、SimpleLayoutView クラスのインスタンスも作成され、この時、初期化メソッド initWithFrame: が呼ばれることになります。このクラスでは、initialize メソッドも実装されていることに注意してください。このメソッドは、クラスオブジェクトが作られる時に呼び出されます。
このメソッドは、initialize が呼ばれたのがこのクラスであることを確認し、そうなら共有されるカラーパネルが透明度スライダーも表示するように指定しているだけです。
さて、初期化メソッドは以下のようになっています。
ここでは、配置スタイルのデフォルト値を設定しているだけです。
SimpleLayoutView クラスには、drawRect: メソッドがありません。このビューは描画を一切行わないということです。「Add」ボタンをクリックすると正方形が表示されます。これはどうやって表示されるのでしょうか。「Add」ボタンが押されると、以下のアクションメソッドが呼ばれます。
このメソッドは、このクラスで定義されている viewToBeAdded というメソッドを呼び出し、そこから返されたビューを下位ビューとして追加し、後は配置をもう一度計算させているだけです。
このメソッドは、単に NSBox インスタンスを作成して、それを返しています。BOXWIDTH と BOXHEIGHT はこのファイルの先頭で定義されている定数です。
setBoxType: の引数の定数 NSBoxCustom は、Mac OS X v10.5 で追加されたものであることに注意してください。これはボックス設定メソッドによってボックスの外観が完全に決定されることを指定します。Apple のヒューマンインターフェイスガイドラインを自動的に適用しないようになっています。よって、ここで設定した項目が無視されることはありません。次に境界線引くように設定しています。そしてタイトルなしにしています。次に塗りつぶし色を、真ん中の下のカラーウェルで設定したものにしています。それから作成したボックスを返します。このなかで、ユーザーの操作で変えられるのは、カラーウェルで設定した色だけです。
こうして作られたボックスが返され、それがビューの下位ビューとして追加されます。描画はこうして追加されたボックスによって自動的に(プログラマとは関係なく AppKit の実装によって)行われることになります。
次に、「Remove」ボタンが押された時に呼ばれるアクションメソッドを見てみます。
これは下位ビューのリストを取得して、その最後のオブジェクト(すなわち、最後に追加されたボックス)を取得し、それに上位ビューから除去されるように命令しています。これによってそのビューは上位ビュー(すなわち、このクラスのインスタンス)の下位ビューリストから除去され、解放されることになります。そして、その後で配置を再計算しています。
追加と除去とは別ですが、ここで左下のマトリックスで、配置スタイルが変更された時に呼ばれるメソッドも見ておきましょう。
これは、タグに設定された値を setLayoutStyle: に渡しているだけです。
単に、今の配置スタイルと違っていたら、新しいレイアウトスタイルを設定しているだけです。ここでも、layout メソッドが最後に呼ばれています。このメソッドが実際の表示に関わる移動を行っているのです。さらに、このクラスでは、setFrameSize: メソッドがオーバーライドされています。それは、フレームサイズが変更された時に、配置が再計算されるようにするためです。
直前で見たように、サブビューの追加・除去、配置スタイルの変更、フレームの変更すべてが、最終的に layout メソッドを呼び出して、配置の再計算などを行わせていました。このメソッドが、このサンプルの中心といえます。
全体的な構造自体は、非常に簡単です。まず現在の下位ビューすべてを取得します。その後、配置スタイルを取得して、それぞれで処理しています。したがって、行から列へ、列からグリッドへ、など、設定された状態によって、それぞれ再計算するのではなく、現在の設定値にしたがって、最初からすべてを計算しなおすようになっています。このサンプルではすでに作ったボックスの色を変えるような方法がないですが、そういうものがあった場合、非常に無駄が多いことになってしまうかもしれません。このような形がいいのか、その時に変更された状態間の相違だけを計算するのがいいのかは、アプリケーションしだいでしょう。ただし、このようにモデルと表示時の計算を分離すればするほど、後の拡張や修正などの扱いが簡単になります。
あと、この switch 文では、default: ラベルで何も行われていませんが、アプリケーションを作成するときは、NSLog(@"SimpleLayoutView's layout method can't undersatand passed layout style"); などのようにして、想定外の値が渡されてしまった場合に気がつくようにしておくのが良いかもしれません。また、余談ですが、case ラベルで、追加処理が必要なものを前に書いて、break 文なしで、次のラベルへとわざと進入させることがあります。こういう時は、/* FALLTHROUGH */(突き抜ける)というコメントを付けるのが慣例です。これを付けることで、break 忘れではなく意図であることをはっきりさせます。
それでは、各処理の内容を個別に見ていきましょう。
まず、デフォルトの列スタイルです。まず下中央の点を計算しています。それから下位ビューそれぞれに対して、繰り返しを行っています。この for ( in ) というスタイルは、Objective-C 2.0 言語でサポートされた高速列挙であることに注意してください。くわしくは『Objective-C 2.0 プログラミング言語』を見てください。
開始点にしたがってボックスのサイズを計算し、それからアニメーションを行うアニメーターを取得し、それに位置の変更を伝えています。integralRect は、このクラスで定義されているメソッドですが、[self convertRectFromBase:NSIntegralRect([self convertRectToBase:rect])] を返しているだけです。つまり基準座標系における整数長方形に長方形を変換しています。SEPARATION はファイルの先頭で定義されている定数で 10.0 です。これは積み上げるときに、ボックスの間にすき間をあけるためのものです。
さらっとアニメーターと書きましたが、このメソッドは、Mac OS X v10.5 で導入された NSAnimatablePropertyContainer プロトコルのメソッドで、プロパティの変更に対して暗黙のアニメーションを開始する代理オブジェクトを返すものです。このように、暗黙のアニメーションを行うには、複雑な設定はなにもなく、アニメーターを取得して、以前と同様なメソッドを使って、移動先のプロパティを設定してやるだけです。
他の場合も、基本的な流れは同じです。コメントの翻訳で十分わかると思います。
この場あ
こうして、配置が計算されれば、組み込みの機能によって、非同期で新しい位置へとアニメーションが行われることになります。アニメーターを取得して、それに設定メソッドを呼び出しただけで、ほとんど追加のコード作業は必要ありません。
このサンプルでは、アニメーターの取得による暗黙のアニメーションを扱っています。これは以前の設定とほとんど変わらずに、組み込み機能が勝手にアニメーションを行ってくれるものです。アニメーションはもっと詳細に扱うこともできます。さらに進んだアニメーションについては、『Core Animation プログラミングガイド』を見てください。
管理人:神吉 秀典 E-mail: