LoginSignup
3
3

More than 5 years have passed since last update.

NSSplitViewの dividerにボタンを追加する

Last updated at Posted at 2014-09-11

目標

xcodeのパレットみたいなものを作りたい。

スクリーンショット 2014-09-11 11.07.46.png
画面上部にある4つのアイコンはボタンで、下段の表示を切り替えるタブの役割。アイコンが並んでいる横長の白い四角の領域は NSSplitViewの dividerで、ドラッグして上下させることができる。

これをどんな風に作ったらいいだろう、という記録。

作業

NSSplitViewそのものにボタンを乗せるアプローチがうまくいかなかったので、ボタンを載せたカスタムビューを別途用意して、それを NSSplittViewのスーパービューに配置し、ちょうど dividerの上に来るように配置する戦略を取ってみた。これで合ってるかどうかはなんとも言えない。

まず http://stackoverflow.com/questions/11593541/how-to-add-buttons-to-a-nssplitter-handle を参考に

  • NSSplitterのサブクラス MySplitViewを作る
  • インターフェースビルダで NSSplitViewを配置、Custom Classを MySplitViewにする
  • NSWindowの外に Custom Viewを配置。 その上にボタンセルの NSMatrixを置く。NSMatrixは MySplitViewにアウトレットを用意してつないでおく。

こんな感じ。
スクリーンショット 2014-09-11 14.21.40.png

スクリーンショット 2014-09-11 14.25.53.png

つぎに MySplitViewのメソッドを上書きする。

awakeFromNibでボタンの乗ったカスタムビューをスーパービューに追加する。 ※ この辺あんまり綺麗じゃない気がしている。

drawDividerInRect:, dividerThicknessで dividerの大きさを決めて描画する。描画時に updateToolbarPositionを呼んでボタンの置かれたCustom Viewの位置を更新。

※ adjustSubviewsはこの例では使われていない。

MySplitViewの実装
-(void)awakeFromNib {
    [self.superview addSubview:self.buttonMatrixView];
}

-(void)drawDividerInRect:(NSRect)rect
{
    [[NSColor grayColor] set];
    NSRectFill(rect);
    [self updateToolbarPosition];
}

-(CGFloat)dividerThickness
{
    return 20.0; // ツールバーの高さ + 上下マージン
}

-(void)adjustSubviews
{
    [super adjustSubviews];
    [self updateToolbarPosition];
}

-(void)updateToolbarPosition
{
    NSRect frame;

    frame.origin.x = (self.frame.size.width - self.buttonMatrixView.bounds.size.width)/2;
    frame.origin.y = self.bounds.size.height - [self positionOfDividerAtIndex:0];
    frame.size     = self.buttonMatrixView.bounds.size;

    [self.buttonMatrixView setFrame:frame];
}


// ref. https://github.com/malcommac/NSSplitView-Animatable

- (CGFloat)positionOfDividerAtIndex:(NSInteger)dividerIndex
{
    while (dividerIndex >= 0 && [self isSubviewCollapsed:[[self subviews] objectAtIndex:dividerIndex]])
        dividerIndex--;
    if (dividerIndex < 0)
        return 0.0f;

    NSRect priorViewFrame = [[[self subviews] objectAtIndex:dividerIndex] frame];
    return [self isVertical] ? NSMaxX(priorViewFrame) : NSMaxY(priorViewFrame);
}

カーソルの形状やcollapse対応などはしていないのでここままでは不十分だけど、それっぽいものは大体作れたと思う。

スクリーンショット 2014-09-11 14.29.22.png

参考

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3