d.hetima RSSフィード

2008-03-14

Cocoa アプリで Cover Flow を使う方法

SafariStand 3.0L159 で History Flow なる履歴閲覧機能を付けたわけですが、コアである Cover Flow の部分。ゼロから作ったわけではありません。こんなもん作る気になれませんw作れませんww。システムにこっそり用意されていました。その名は「IKImageFlowView」。ImageKit.framework に定義されています。これは Quartz.framework のサブ framework なので、使用するには Quartz.framework をリンクします。

基本的な使用法は IKImageBrowserView と似ています。delegate と datasource があり、IKImageBrowserItem Protocol に合致するオブジェクトを渡してコンテンツを作ります。

nib に NSView を配置してカスタムクラスを「IKImageFlowView」と記入*1。awakeFromNib あたりでこのインスタンスに対して setDelegate: と setDataSource: を設定。

reloadData を実行すると、dataSource の

-(NSUInteger)numberOfItemsInImageFlow:(id)fview;
-(id)imageFlow:(id)fview itemAtIndex:(NSUInteger)idx;

が呼ばれるので、アイテムの数を返したり、IKImageBrowserItem Protocol に合致するオブジェクトを返したりします。IKImageBrowserItem に関しては IKImageBrowserView を調べれていけば分かると思います。

delegate には

//選択項目が変更されたらこれ
-(void)imageFlow:(id)fview didSelectItemAtIndex:(NSUInteger)idx
//項目がダブルクリックされたらこれ
-(void)imageFlow:(id)fview cellWasDoubleClickedAtIndex:(NSUInteger)idx

などが呼ばれます。

他にも

//たぶん datasource
imageFlow:(id)fview writeItemsAtIndexes:(NSIndexSet *)indexes toPasteboard:(NSPasteboard *)pasteboard
imageFlow:(id)fview removeItemsAtIndexes:(NSIndexSet *)indexes

//たぶん delegate
imageFlow:(id)fview didLoadItemAtIndex:(NSUInteger)idx
imageFlowDidStabilize:(id)fview
imageFlow:(id)fview startResizingWithEvent:(NSEvent*)event

といったメソッドが呼ばれる可能性があります。今回は調査していないので詳細は不明です。返り値も分からないし、引数の型もこれで合っているかは保証できません。いくつかは IKImageBrowserView と似ているので想像はつきますが。

imageFlow:startResizingWithEvent: はちょっと試しました。[imageFlowView setShowSplitter:YES] とすると、ビューの下部にリサイズバーが表示されるようになり、そこをクリックすると imageFlow:startResizingWithEvent: が呼ばれます。しかし、そこから先はどうしたらいいかさっぱり分かりません。ドラッグしてもリサイズされません。このメソッドを実装しない場合も同様でした。

プログラムから項目選択を行うには IKImageFlowView に対して setSelectedIndex:(unsigned int)idx を呼びます。他の機能は class-dump して調べてください。

ちなみに imageFlow:cellWasDoubleClickedAtIndex: を delegate で実装しない場合、imageRepresentationType で IKImageBrowserPathRepresentationType を返し、imageRepresentation でファイルパスを返すと、項目をダブルクリックしたらファイルパスがさすファイルを対応アプリケーションで開きます。

実際に組み込みたい場合は Quartz.framework をリンクし、適当な場所で IKImageFlowView を宣言しておきます。nib で作る場合は id で良いので宣言は無くても構いませんが。

@interface IKImageFlowView : NSOpenGLView
{
    id _dataSource;
    id _dragDestinationDelegate;
    id _delegate;
    void *_reserved;
}
+ (BOOL)flowViewIsSupportedByCurrentHardware;
+ (void)setImportAnimationStyle:(unsigned int)fp8;
- (void)setSelectedIndex:(unsigned int)fp8; //選択する
- (void)setShowSplitter:(BOOL)fp8;
- (void)reloadAllCellsData;
- (void)reloadCellDataAtIndex:(int)fp8;
- (void)reloadData;
- (id)delegate;
- (void)setDelegate:(id)fp8;
- (id)dataSource;
- (void)setDataSource:(id)fp8;
- (unsigned int)itemsCount;
- (id)cells;
- (unsigned int)selectedIndex;
- (unsigned int)focusedIndex;
- (id)backgroundColor;
- (id)cellBackgroundColor;
//などなど
@end

というわけでものすごく楽に実装できました。undocumented なので at your own risk ですけど。

History Flow

*1:initWithFrame: する方法ではクラッシュしたのでそれ以上調査せず

hsatouhsatou 2008/03/15 06:06 素晴らしい機能を提供して頂きありがとうございます。
ここに書いていいか分かりませんが
使ってみて気になった事がありました。

HistoryFlowの表示で
デフォルトで履歴一覧にフォーカスがないので
カーソルでヒストリーを移動しながら
CoverFlowの表示を切り替えを
する事ができません。
タブを押してフォーカスを移動するとできますが。
最初からどこかにフォーカスがあったら
便利かなと思いました。

ffff 2008/03/15 08:56 右クリックでcoverflow表示が小さくオーバーラップ表示できたらいいなと思ったのですが、背景を透明にすることってできないのでしょうか?

なまえなまえ 2008/03/16 22:22 有用な情報ありがたいです。
IKImageFlowViewのheightは小さすぎるとたまに止まりますね。
ある程度のサイズで縮小を止めておくのがいいようです。

一つ質問なのですが、
delegateやdatasourceのメソッドはどうやって調べておられるのですか?
これもclass-dumpで出たりするのでしょうか?
差し支えなければご返答お願いします。

hetimahetima 2008/03/17 01:05 delegateとdatasourceのメソッドはclass-dumpでは出てこなかったので、「imageFlow」という文字列でImageKit.frameworkのバイナリを検索して、それっぽいものを拾い上げました。strings コマンドでも良いと思います。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト

コメントを書くには、なぞなぞ認証に回答する必要があります。