【问题标题】:Programmatically set up NSTextView inside NSScrollView以编程方式在 NSScrollView 中设置 NSTextView
【发布时间】:2014-09-08 07:08:41
【问题描述】:

我正在尝试以编程方式在NSScrollView 中设置NSTextView,但遇到了问题。

具体来说,我无法滚动文本视图;滚动视图似乎认为“这就是全部”。当您尝试向下滚动查看其余内容(不释放)时,结果如下:

一旦你释放,滚动视图就会反弹回来,所以这不是图形故障;它只是在框架高度处剪辑文本视图。

我尝试过使用the Apple 'Text In ScrollView' docssetVerticallyResizable: 等进行试验。

代码:

- (void)configureValueTextView
{
    NSScrollView *vfContainer = [[NSScrollView alloc] initWithFrame:(NSRect){0,0,50,50}];
    vfContainer.hasVerticalScroller = YES;
    vfContainer.hasHorizontalScroller = NO;
    vfContainer.translatesAutoresizingMaskIntoConstraints = NO;
    _valueFieldContainer = vfContainer;
    vfContainer.borderType = NSLineBorder;

    NSTextView *valueField = _valueField = [[NSTextView alloc] initWithFrame:(NSRect){0,0,vfContainer.contentSize}];
    valueField.delegate = self;
    valueField.minSize = (NSSize){0,0};
    valueField.maxSize = (NSSize){FLT_MAX, FLT_MAX};
    [valueField setVerticallyResizable:YES];
    [valueField setHorizontallyResizable:YES];

    valueField.translatesAutoresizingMaskIntoConstraints = NO;
    valueField.string = _value ? _value : @"";
    valueField.editable = YES;
    valueField.textContainer.containerSize = (NSSize) { vfContainer.contentSize.width, FLT_MAX };
    valueField.textContainer.heightTracksTextView = NO;

    vfContainer.documentView = valueField;
    [vfContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[_valueField]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_valueField)]];
    [vfContainer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[_valueField]-(0)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_valueField)]];
}

框架稍后会调整为正确的值,

[_valueFieldContainer setFrame:(NSRect){kKEFormFieldViewKeyWidth + 10, 0, valueFieldWidth, h}];
[_valueField setFrame:(NSRect){0, 0, valueFieldWidth, h}];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(0)-[_valueFieldContainer]-(5)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_valueFieldContainer)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(0)-[_keyField]-(10)-[_valueFieldContainer]-(0)-|" options:0 metrics:nil views:@{@"_keyField": _keyField, @"_valueFieldContainer": _valueFieldContainer}]];

就是这样。欢迎提示!

【问题讨论】:

  • 您已经设置了一个垂直约束,使文本视图与其父视图(滚动视图的剪辑视图)的高度相匹配。我认为这就是问题所在。您是否尝试过仅使用旧式自动调整大小掩码而不是文本视图的自动布局?
  • 我尝试移除垂直限制,但当我这样做时,滚动视图变为空白。我将文本视图切换到旧的自动布局并做了valueField.autoresizingMask = NSViewWidthSizable; 并删除了两个自动布局的东西,突然一切都完美了。介意写一个答案让我接受吗?

标签: objective-c macos cocoa nstextview nsscrollview


【解决方案1】:

Swift 4 示例。

class ViewController: NSViewController {

   fileprivate lazy var textStorage = NSTextStorage()
   fileprivate lazy var layoutManager = NSLayoutManager()
   fileprivate lazy var textContainer = NSTextContainer()
   fileprivate lazy var textView: NSTextView = NSTextView(frame: CGRect(), textContainer: textContainer)
   fileprivate lazy var scrollview = NSScrollView()

   override func viewDidLoad() {
      super.viewDidLoad()
      view.addSubview(scrollview)
      // Set `true` to enable horizontal scrolling.
      setupUI(isHorizontalScrollingEnabled: false) 
      setupLayout()
      setupTextStack()
   }
}

extension ViewController {

   fileprivate func setupTextStack() {
      textStorage.addLayoutManager(layoutManager)
      layoutManager.addTextContainer(textContainer)
   }

   fileprivate func setupUI(isHorizontalScrollingEnabled: Bool) {

      let contentSize = scrollview.contentSize

      if isHorizontalScrollingEnabled {
         textContainer.containerSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
         textContainer.widthTracksTextView = false
      } else {
         textContainer.containerSize = CGSize(width: contentSize.width, height: CGFloat.greatestFiniteMagnitude)
         textContainer.widthTracksTextView = true
      }

      textView.minSize = CGSize(width: 0, height: 0)
      textView.maxSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
      textView.isVerticallyResizable = true
      textView.isHorizontallyResizable = isHorizontalScrollingEnabled
      textView.frame = CGRect(width: contentSize.width, height: contentSize.height)
      if isHorizontalScrollingEnabled {
         textView.autoresizingMask = [.width, .height]
      } else {
         textView.autoresizingMask = [.width]
      }

      scrollview.borderType = .noBorder
      scrollview.hasVerticalScroller = true
      scrollview.hasHorizontalScroller = isHorizontalScrollingEnabled
      scrollview.documentView = textView
   }

   fileprivate func setupLayout() {
      scrollview.translatesAutoresizingMaskIntoConstraints = false

      var customConstraints = [NSLayoutConstraint]()
      // `LayoutConstraint` - custom type with convenience methods. 
      customConstraints += LayoutConstraint.pinInSuperview(scrollview)
      view.addConstraints(customConstraints)
   }
}

【讨论】:

  • 这非常有用。谢谢。
  • 很棒的工作,谢谢,在 Swift 5 和 macOS 10.15 中仍然有用。我只需要更改框架的 CGRect,如下所示:textView.frame = CGRect(x: scrollView.frame.origin.x, y: scrollView.frame.origin.y, width: contentSize.width, height: contentSize.height).
【解决方案2】:

您设置了垂直约束,使文本视图与其父视图(滚动视图的剪辑视图)的高度相匹配。我认为这就是问题所在。如果您只是完全删除它,那么您在垂直方向上就会完全模棱两可,并且文本视图可以在任何地方结束。我认为您只需将其顶部边缘固定到超级视图的顶部即可逃脱 - 即@"V:|[_valueField]"。如果文本视图提供固有高度,那将起作用,但我不确定它是否有效。为文本视图的高度设置一个约束,使其与文本布局管理器生成的内容相匹配,这是非常重要的。

鉴于您真的不需要布局中的任何特殊内容,您可以只使用旧式自动调整大小掩码而不是自动布局。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    相关资源
    最近更新 更多