1

水平スクローラーの位置に関係なく、常に同じ列を表示するように NSTableView を取得するにはどうすればよいですか? 一番右の表示列には、カスタム セル ビューがあります。これらのカスタム ビューで描画される内容を水平スクローラーで制御したいと考えています。垂直スクロールは正常に機能するはずです。

私はいくつかのアプローチを試みましたが、あまり成功しませんでした。たとえば、水平スクローラーのノブの比率を制御するには、テーブル ビューを広くしたり、スクロール ビューにドキュメント ビューが実際よりも広いと認識させたりします。1 つの方法は、次のように NSClipView をサブクラス化し、-documentRect をオーバーライドすることです。

-(NSRect)documentRect {
    NSRect rect = [super documentRect];
    rect.size.width += [[NSApp delegate] hiddenRangeWidth];
    return rect;
}

ただし、スクローラー ノブは正常に表示され、テーブル ビューを移動せずに右にドラッグできますが、別の方向にスクロールを開始すると、ノブが左端に戻ります。また、水平スクローラーを自動的に表示できないという問題もあります。これは、カスタム クリップ ビューだけでなく、元のクラスでも発生します。これらの問題は関連している可能性がありますか?

また、ドキュメント ビューを、クリップ ビューとテーブル ビューの間のプロキシとして機能するカスタム ビューに置き換えてみました。その -drawRect: は、テーブル ビューの -drawRect: を呼び出します。ただし、何も描かれていません。これは、テーブル ビューにスーパービューがなくなったためだと思います。テーブル ビューがこのプロキシ ビューにサブビューとして追加された場合は、一緒に移動します。水平軸で静止させるにはどうすればよいですか?

繰り返しになりますが、

  1. 水平スクローラーの位置に関係なく常に同じ列を表示しながら、テーブルビューをスクロール可能にする最良の方法は何ですか?
  2. スクローラーの位置とノブの比率を取得する最良の方法は何ですか? NSClipView から NSViewBoundsDidChangeNotification のオブザーバーを追加する必要がありますか?
4

1 に答える 1

0

スクロール ビューとテーブル ビューを正常に動作させ、NSScroller を追加することで、最終的に問題を解決することができました。スクローラーを簡単に非表示にするために、Auto Layout を使用して Interface Builder に追加することにしました。(オブジェクト ライブラリにはスクローラーが含まれていませんが、カスタム ビューを追加して、そのクラスを NSScroller に設定できます。) スクローラーの高さを制約として設定し、スクローラーと制約をコードのアウトレットにバインドします。

@property (nonatomic, retain) IBOutlet NSScroller *scroller;
@property (nonatomic, unsafe_unretained) IBOutlet NSLayoutConstraint *scrollerHeightConstraint;

これで、必要に応じてスクローラーを表示または非表示にすることができます。

if (_zoomedIn) {
    _scrollerHeightConstraint.constant = [NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleOverlay];
    [_scroller setKnobProportion:(_visibleRange / _maxVisibleRange)];
    [_scroller setDoubleValue:_visibleRangePosition];
    [_scroller setEnabled:YES];
} else {
    _scrollerHeightConstraint.constant = 0.0;
}

ここで、プロパティ visibleRange、maxVisibleRange、および visibleRangePosition は、それぞれ可視範囲の長さ (スクローラー ノブで表される)、合計範囲 (スクローラー スロットで表される)、および可視範囲の開始 (ノブの位置) です。これらは、スクローラーの送信アクションを Interface Builder の次のメソッドにバインドすることで読み取ることができます。

- (IBAction)scrollAction:(id)sender {
    switch (self.scroller.hitPart) {
        case NSScrollerNoPart:
            break;
        case NSScrollerDecrementPage:
            _visibleRangePosition = MAX(_visibleRangePosition - _visibleRange / _maxVisibleRange, 0.0);
            self.scroller.doubleValue = _visibleRangePosition;
            break;
        case NSScrollerIncrementPage:
            _visibleRangePosition = MIN(_visibleRangePosition + _visibleRange / _maxVisibleRange, 1.0);
            self.scroller.doubleValue = _visibleRangePosition;
            break;
        case NSScrollerKnob:
        case NSScrollerKnobSlot:
            _visibleRangePosition = self.scroller.doubleValue;
            break;
        default:
            NSLog(@"unsupported scroller part code %lu", (unsigned long)self.scroller.hitPart);
    }
    // Make the custom cell views draw themselves here.
}

ジェスチャでスクロールを機能させるには、カスタム セル ビュー クラスに -scrollWheel: を実装する必要があります。

- (void)scrollWheel:(NSEvent *)event {
    if (event.deltaX != 0.0) {
        NSScroller *scroller = appDelegate.scroller;
        if (scroller.isEnabled) {
            double delta = event.deltaX / (NSWidth(scroller.bounds) * (1.0 - scroller.knobProportion));
            scroller.doubleValue = MIN(MAX(scroller.doubleValue - delta, 0.0), 1.0);
        }
    }
    if (event.deltaY != 0.0) {
        [self.nextResponder scrollWheel:event];
    }
}

イベントをスクローラーに渡すことができたと思ったのですが、どうやらイベントを処理していないようです。上記のコードは跳ね返りを処理していないようで、勢いスクロールは常に機能するとは限りません。ノブが動きの途中で止まることがあります。これは、スクローラーのスタイルがデフォルトで NSScrollerStyleLegacy になっていることに関係していると思います。NSScrollerStyleOverlay に設定すると、レイアウトの変更が必要になるため、まだ試していません。

もう 1 つの問題は、スクロール ビューの場合のように、隅でスクローラーが互いに混ざり合わないことです (以下を参照)。多分 NSScrollerStyleOverlay もこれを修正するでしょう。

スクローラーの間のコーナー

于 2014-11-19T20:38:28.777 に答える