swift 为什么NSTextView在异步加载时滚动到底部?

ss2ws0br  于 11个月前  发布在  Swift
关注(0)|答案(3)|浏览(126)

我有一个简单的macOS应用程序的Swift代码:

// ViewController.swift

import Cocoa

let string = (1...30).map { "line \($0)" }.joined(separator: "\n")

class ViewController: NSViewController {
  private func setupTextView() {
    let scrollView = NSTextView.scrollableTextView()
    guard let textView = scrollView.documentView as? NSTextView else {
      return
    }
    
    textView.string = string
    
    /**
     * If I comment the following line, it won't scroll.
     */
    textView.layoutManager?.allowsNonContiguousLayout = true
    
    view.addSubview(scrollView)
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
      view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
      view.topAnchor.constraint(equalTo: scrollView.topAnchor),
      view.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
      view.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
    ])
  }
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    /**
     * If I execute self.setupTextView() directly without DispatchQueue.main.async, it won't scroll.
     */
    DispatchQueue.main.async {
      self.setupTextView()
    }
  }
}

字符串
当应用程序启动时,文本视图自动滚动到底部,与我的意图相反,它保持未滚动,以便第一行可见。
有趣的是,如果我注解掉textView.layoutManager?.allowsNonContiguousLayout = true,或者将self.setupTextView()移出xmlc块,它会像预期的那样工作。
只是想了解滚动的根本原因是什么,以及避免它的最佳实践是什么(考虑到我需要设置它,需要allowsNonContiguousLayout)?

nbewdwxp

nbewdwxp1#

您可以将allowsNonContiguousLayout放入一个专用的异步块中,以防止不必要的滚动,而无需将其注解掉:

DispatchQueue.main.async {
    textView.layoutManager?.allowsNonContiguousLayout = true
}

字符串
代码的其余部分将是相同的。

chy5wohz

chy5wohz2#

scrollView.frame.size(width = 0, height = 0)。行数和滚动位置无法正确计算。当滚动视图稍后调整大小时,滚动位置仍然不正确。
我认为非连续布局计算行数的方式不同。
当它的超级视图可见的时候,这个块会添加滚动视图。我认为框架大小,行数和滚动位置是以不同的顺序计算的。
解决方案:将滚动视图的帧大小设置为实际值。
scrollView.frame = view.bounds

scrollView.frame.size = NSSize(width: 100, height: 100)

9udxz4iz

9udxz4iz3#

让我试试。为了避免这个问题,你可以修改设置,在文本视图布局之前设置allowsNonContiguousLayout属性。尝试同步设置文本视图和配置其属性,而不依赖于DispatchView.main.jsp。像这样。

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Synchronously set up the text view and configure its properties
    self.setupTextView()
}

字符串
通过同步设置文本视图,allowsNonContiguousLayout属性将在布局过程开始之前应用,从而有望防止意外的滚动行为。

相关问题