2
  • 私の目標

1 つのウィンドウでアプリを作成します。ウィンドウのルート ビューは、4 つのボタンを持つ 2 つの画像になります。これらの 4 つのボタンはそれぞれ、異なる (メイン) ビューを表示します。各メイン ビューには他の (サブ) ビューが表示され、各メイン ビューとサブ ビューはルート ビューに「戻る」ことができる必要があります。

  • 私がやったこと(AppleのViewControllerプロジェクトに基づいています)

    • 尊敬される XIB ファイルを使用して1NSWindowControllerと 4を作成しました。NSViewController

    • AppDelegate は、ウィンドウとルート ビューを含む nib を持つオブジェクトを割り当て/初期化し、その上でメソッドをNSWindowController呼び出します。showWindow

    • のサブクラスにNSWindowControllerは 2 つの ivar があります。1 つNSViewは IB にバインドされたルート ビューを表し、もう 1 つNSViewControllerは現在のビュー コントローラーを表します。
    • ボタンタグに応じてビューを変更するメソッドに 4 つのボタンをバインドしました。

これは、AppleのViewControllerプロジェクトがそれを実装する方法ですhttp://pastie.org/private/zmqpzgnudgovagwigal8dq

それにもかかわらず、これは私にはうまくいきません。ルートビューの上にビューを追加するだけです。

ご覧のとおり、私は少し迷っています。お気軽にアイデアを共有してください!

4

1 に答える 1

9

1つのアプローチは、NSBoxを使用することです。 このデモの完全なコードはgithubにあります。下部のリンクを参照してください。

入門

Cocoaアプリケーションテンプレートを使用して、Xcodeで新しいプロジェクトを開始します。適切なプレフィックスを使用してください。StackOverflowDemoにはSODを使用します。

他の作業を行う前に、テンプレートの一部としてプロジェクトに自動的に追加されたファイルにいくつかの小さな変更を加えます。

  • MainMenu.xib:NSWindowを削除します。
  • SODAppDelegate.h:次の行を削除します:@property (assign) IBOutlet NSWindow *window;

例を単純化するために、左側にクリック可能なアイテム(簡単にするためにボタンなど)の列を持つ単一のウィンドウが必要だとします。

SODWindowController

NSWindowControllerプロジェクトにサブクラスを追加することから始めます。対応するを必ず含めてくださいXIB。開いSODWindowController.xibて、ウィンドウの左側に4つのボタン(私は正方形のボタンを使用)を追加し、NSBoxウィンドウの残りの部分を埋めて追加します。この時点で、あなたはこのようなものを少し持っているでしょう。

ステップ1

ボックスのcontentViewを、レイヤーの背景色が。のレイヤーホスティングビューに設定しました[NSColor greenColor]。そうしないと、ボックスがまったく表示されないため、これを実行しました。ボックスは、ビューをスワップインおよびスワップアウトするためにのみ使用されるように構成されています。このようにボックスを構成するには、Interface Builderでとを選択NSBoxし、属性インスペクターでをに設定し、Title PositionをにNone設定Border TypeしますNone

今、SODWindowController.mで、スタブを交換してくださいinitWithWindow:

- (id)initWithWindow:(NSWindow *)window
{
    self = [super initWithWindow:window];
    if (self) {
        // Initialization code here.
    }

    return self;
}

別の指定された初期化子を使用:

- (id)init
{
    self = [super initWithWindowNibName:@"SODWindowController"];
    {

    }
    return self;
}

これにより、再入力(および潜在的にXIBの名前の入力ミス)を回避できます。

SODWindowControllerさらに、行の直後にクラス拡張子を追加します

#import "SODWindowController.h"

で、自分自身に:SODWindowController.mを与えますIBOutletNSBox

@interface SODWindowController ()
@property (nonatomic, strong, readwrite) IBOutlet NSBox *box;
@end

Interface BuilderでSODWindowController.xib、ボックスアウトレットを開き、追加したものを指すように設定しますNSBox

SODWindowControllerをSODAppDelegateに追加します

ここで、を追加しSODWindowControllerます:すぐ下SODAppDelegateに行を追加します:SODAppDelegate.m#import "SODAppDelegate.h"

#import "SODWindowController.h"

@interface SODAppDelegate ()
@property (nonatomic, strong, readwrite) SODWindowController *windowController;
@end

これで、ウィンドウを次の場所に作成するように設定できます-[NSApplication applicationDidFinishLaunching:]

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    self.windowController = [[SODWindowController alloc] init];
    //notice that we don't have to do anything awkward like use initWithWindowNibName:
    [self.windowController showWindow:nil];
}

この時点で、アプリを実行すると、ウィンドウが表示されます。

すばらしいですが、ユーザーが戻ることができるように、4つの異なるボタンの異なるビューと履歴についてはどうでしょうか。

SODViewControllers

4つのビューのそれぞれについて、NSViewControllerサブクラスを作成します。私SODCoffeeViewControllerの名前をSODTeaViewController、、、SODJavaViewControllerと呼びますSODMeViewController

それぞれで、自動生成された指定された初期化スタブを置き換えます

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialization code here.
    }

    return self;
}

- (id)init
{
    self = [super initWithNibName:@"SODCoffeeViewController" bundle:nil];
    if (self) {
    }
    return self;
}

もちろん、それぞれに適切なNibName引数を代入します。以前と同様に、これにより、そのペン先に関連付けられているファイルの外部に「@"MyNibName」と入力する必要がなくなります。

SODViewControllersをSODWindowControllerに追加します

次に、4つすべてのView ControllerをにインポートしますSODWindowController:行を追加します

#import "SODCoffeeViewController.m"
#import "SODTeaViewController.m"
#import "SODJavaViewController.m"
#import "SODTeaViewController.m"

これらSODWindowControllerの各オブジェクトの1つが必要です。クラス拡張NSArrayにプロパティを追加する最も簡単な方法SODWindowController

@property (nonatomic, strong, readwrite) NSArray *viewControllers;

-[SODWindowController init]と行を追加の実装で

- (id)init
{
    self = [super initWithWindowNibName:@"SODWindowController"];
    if (self) {
        NSMutableArray *mutableViewControllers = [NSMutableArray array];
        [mutableViewControllers addObject:[[SODCoffeeViewController alloc] init]];
        [mutableViewControllers addObject:[[SODTeaViewController alloc] init]];
        [mutableViewControllers addObject:[[SODJavaViewController alloc] init]];
        [mutableViewControllers addObject:[[SODMeViewController alloc] init]];
        self.viewControllers = [mutableViewControllers copy];
    }
    return self;    
}

これで、表示する4つのビューごとに1つのビューコントローラーがあり、ウィンドウにある4つのボタンと同じように配列で並べられています。さらに重要なのは、4つのボタンのタグと同じように並べられていることです。...タグを設定した後、つまり。

SODWindowController.xibInterface Builderで開き、一番上のボタンのタグを、上から2番目のボタンなどに設定し0ます1

戻って、クラス拡張子SODWindowController.mにを追加します。IBActionSODWindowController

- (IBAction)showPane:(id)sender;

このメソッドを次のように定義SODWindowController @implementionします。

- (void)showPane:(NSButton *)sender
{
    [self showPaneAtIndex:sender.tag];
}

以上です!

...もちろん定義する場合を除き-[SODWindowController showPaneAtIndex:]ます。ただし、その前に、の4つのボタンのアクションをオンに設定SODWindowController.xibshowPane:File's Ownerください。

それが完了したら、次のように定義showPaneAtIndex:します。

- (void)showPaneAtIndex:(NSInteger)index
{
    NSViewController *viewController = (NSViewController *)self.viewController[(NSUInteger)index];
    [self.box setContentView:viewController.view];
}

これで、いずれかのボタンが押されるたびに、対応するViewControllerのビューがボックスのコンテンツビューとして設定されます。

おそらく、ウィンドウが表示されたらすぐに、最上位のView Controllerのビュー(SODCoffeeViewController's)を表示する必要があります。これを実現するには、の現在の定義を次のように置き換えます-windowDidLoad

- (void)windowDidLoad
{
    [super windowDidLoad];
    [self showPaneAtIndex:0];
}

歴史

歴史は実際には最も簡単な部分です。私たちが行うことは、私たちの後ろにある(ブラウザの戻るボタンの意味で)1つまたは2つのペインと、私たちの前にある(進むボタンの意味で)ペインの配列を追跡することです。これを行うには、2つの可変配列プロパティをSODWindowControllerクラス拡張に追加します。

@property (nonatomic, strong, readwrite) NSMutableArray *panesBehind;
@property (nonatomic, strong, readwrite) NSMutableArray *panesBefore;

でそれらを初期化します-init

    ...
    self.viewControllers = [mutableViewControllers copy];

    self.panesBehind = [NSMutableArray array];
    self.panesBefore = [NSMutableArray array];
    }
    return self;
}

次に、アクセスする新しい各ペインのインデックスをプッシュする必要があるself.panesBehindので、行を追加します

[self.panesBehind addObject:[NSNumber numberWithInteger:index]];

の定義に-showPaneAtIndex:

-goBackこれにより、-goForwardとヘルパー-canGoBack-canGoForward次のように定義できます。

- (BOOL)canGoBack
{
    return self.panesBehind.count > 0;
}

- (void)goBack
{
    if (self.canGoBack) {
        NSNumber *presentPane = self.panesBehind.lastObject;
        [self.panesBehind removeLastObject];
        [self.panesBefore insertObject:presentPane atIndex:0];
        NSNumber *previousPane = self.panesBehind.lastObject;
        [self.panesBehind removeLastObject];
        [self showPaneAtIndex:previousPane.integerValue];
    }
}

- (BOOL)canGoForward
{
    return self.panesBefore.count > 0;
}

- (void)goForward
{
    if (self.canGoForward) {
        NSNumber *nextPane = [self.panesBefore objectAtIndex:0];
        [self.panesBefore removeObjectAtIndex:0];
        [self showPaneAtIndex:nextPane.integerValue];
    }
}

ただし、これには小さな問題があります。ペインAからB、C、Dに進むと、self.panesBehind次のようになります。

A-->B-->C-->D

そしてself.panesBefore空です。しかし、2つのペインに戻ると、self.panesBehind次のようになります。

A-->B

のようにself.panesBefore見えます

C-->D

この時点でペインEに移動すると、次のself.panesBehindようになります。

A-->B-->E

予想どおりですが、self.panesBeforeそれでも次のようになります

C-->D

これは私たちが望んでいることではありません。このため、行を追加します

[self.panesBefore removeAllObjects];

の終わりまで-showPane:

これらのメソッドを試すには、先に進んで、ので公に宣言し@interfaceSODWindowControllerくださいSODWindowController.h

@interface SODWindowController : NSWindowController
- (void)goForward;
- (void)goBack;
@end

次に、とMainMenu.xibのファイルメニューに2つのメニュー項目を追加します。2つ宣言する:ForwardBackSODAppDelegate.hIBActions

- (IBAction)forward:(id)sender;
- (IBAction)back:(id)sender;

に戻ってMainMenu.xib、[進む]メニュー項目のアクションをに設定し、forward:[First Responder戻る]メニュー項目のアクションをに設定back:しますFirst Responder。最後に、2つのメソッドを定義-[SODAppDelegate forward:]し、次-[SODAppDelegate back:]の対応するメソッドを呼び出しますSODWindowController

- (IBAction)forward:(id)sender
{
    [self.windowController goForward];
}

- (IBAction)back:(id)sender
{
    [self.windowController goBack];
}

完全なソースをダウンロードするには、https://github.com/natechan/ViewSwappingDemoにアクセスしてください。

于 2012-10-16T05:15:07.257 に答える