25

私のアプリは、NSScrollViewドキュメントビューに垂直方向に積み重ねられた多数のNSTextViewsファイルで構成されており、テキストが追加されると、それぞれが垂直方向にサイズ変更されます。

現在、これはすべてコードで管理されています。NSTextViewsサイズは自動的に変更されますが、サイズ変更をで観察し、すべてNSViewFrameDidChangeNotificationの原点が重ならないように再計算し、スーパービュー(スクロールビューのドキュメントビュー)のサイズを変更して、すべてが収まり、スクロールできるようにします。

これは、自動レイアウトの最適な候補であるかのようです。NSLayoutConstraints最初のテキストビューとそのコンテナ、最後のテキストビューとそのコンテナ、および各テキストビューを相互に設定しました。次に、テキストビューが大きくなると、その下のテキストビューの原点が自動的に「プッシュダウン」されて制約が満たされ、最終的にドキュメントビューのサイズが大きくなり、誰もが満足します。

NSTextViewただし、制約ベースのレイアウトでテキストが追加されるときに自動的に拡大する方法はないようです。以前にテキストが入力されたときに自動的に展開されたものとまったく同じNSTextViewものを使用して、高さの制約を指定しない場合、0にデフォルト設定され、表示されません。制約を指定すると、> = 20のような不等式であっても、そのサイズのままになり、テキストが追加されても大きくなりません。

-intrinsicContentSizeこれは、デフォルトでを返すNSTextViewの実装に関係していると思われます(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric)

だから私の質問:テキストのレイアウトに基づいてNSTextViewより意味のあるものを返すようにサブクラス化した場合、自動レイアウトは期待どおりに機能しますか?intrinsicContentSize

intrinsicContentSizeNSTextViewを垂直方向にサイズ変更するための実装に関する指針はありますか?

4

4 に答える 4

31

私は非常によく似た設定に取り組んでいます。テキストコンテンツに合わせて拡張し、自動レイアウトを使用するテキストビューを含むビューの垂直スタックです。

これまでのところ、私はサブクラス化する必要がありましたNSTextView。これはクリーンではありませんが、実際には見事に機能します。

- (NSSize) intrinsicContentSize {
    NSTextContainer* textContainer = [self textContainer];
    NSLayoutManager* layoutManager = [self layoutManager];
    [layoutManager ensureLayoutForTextContainer: textContainer];
    return [layoutManager usedRectForTextContainer: textContainer].size;
}

- (void) didChangeText {
    [super didChangeText];
    [self invalidateIntrinsicContentSize];
}

追加されたときのテキストビューの初期サイズaddSubviewは、不思議なことに、本来のサイズではありません。最初の無効化を発行する方法はまだわかりませんが(フッキングviewDidMoveToSuperviewは役に立ちません)、最終的には理解できると確信しています。

于 2013-01-22T23:15:33.347 に答える
12

NSTextFieldでも同様の問題が発生しましたが、ビューがテキストコンテンツを垂直方向にしっかりと抱きしめたいことが原因であることが判明しました。したがって、コンテンツハグの優先度を他の制約の優先度よりも低い値に設定すると、機能する可能性があります。例えば:

[textView setContentHuggingPriority:NSLayoutPriorityFittingSizeCompression-1.0 forOrientation:NSLayoutConstraintOrientationVertical];

そしてSwiftでは、これは次のようになります。

setContentHuggingPriority(NSLayoutConstraint.Priority.fittingSizeCompression, for:NSLayoutConstraint.Orientation.vertical)
于 2012-07-10T16:56:20.430 に答える
6

Swift3で自動レイアウトを使用して拡張NSTextViewを作成する方法は次のとおりです。ここに画像の説明を入力してください

  • 自動レイアウトにアンカーを使用しました
  • から使用textDidChangeNSTextDelegateます。NSTextViewDelegateに準拠NSTextDelegate
  • アイデアにtextViewedges制約があります。つまり、intrinsicContentSize変更が加えられるたびに、親が拡張されます。scrollView

    import Cocoa
    import Anchors
    
    class TextView: NSTextView {
      override var intrinsicContentSize: NSSize {
        guard let manager = textContainer?.layoutManager else {
          return .zero
        }
    
        manager.ensureLayout(for: textContainer!)
    
        return manager.usedRect(for: textContainer!).size
      }
    }
    
    class ViewController: NSViewController, NSTextViewDelegate {
    
      @IBOutlet var textView: NSTextView!
      @IBOutlet weak var scrollView: NSScrollView!
      override func viewDidLoad() {
        super.viewDidLoad()
    
        textView.delegate = self
    
        activate(
          scrollView.anchor.top.constant(100),
          scrollView.anchor.paddingHorizontally(30)
        )
    
        activate(
          textView.anchor.edges
        )
      }
    
      // MARK: - NSTextDelegate
      func textDidChange(_ notification: Notification) {
        guard let textView = notification.object as? NSTextView else { return }
    
        print(textView.intrinsicContentSize)
        textView.invalidateIntrinsicContentSize()
      }
    }
    
于 2017-05-19T06:31:18.970 に答える
3

コピーと貼り付けの準備ができているクラス。Swift 4.2、macOS 10.14

class HuggingTextView: NSTextView, NSTextViewDelegate {

    //MARK: - Initialization

    override init(frame: NSRect) {
        super.init(frame: frame)
        delegate = self
    }

    override init(frame frameRect: NSRect, textContainer container: NSTextContainer?) {
        super.init(frame: frameRect, textContainer: container)
        delegate = self
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        delegate = self
   }

    //MARK: - Overriden

    override var intrinsicContentSize: NSSize {
        guard let container = textContainer, let manager = container.layoutManager else {
            return super.intrinsicContentSize
        }
        manager.ensureLayout(for: container)
        return manager.usedRect(for: container).size
    }

    //MARK: - NSTextViewDelegate

    func textDidChange(_ notification: Notification) {
        invalidateIntrinsicContentSize()
    }

}
于 2018-11-12T13:36:47.467 に答える