macos - 如何使用 NSViewRepresentable 将 NSTextView 在 SwiftUI View 中垂直居中?

标签 macos swiftui nstextview

我有一个简单的NSViewRepresentable,它包装了NSTextView

struct TextView: NSViewRepresentable {
  typealias NSViewType = NSTextView

  var text: NSAttributedString

  func makeNSView(context: Context) -> NSTextView {
    let view = NSTextView()
    // set background color to show view bounds
    view.backgroundColor = NSColor.systemBlue
    view.drawsBackground = true
    view.isEditable = false
    view.isSelectable = false
    return view
  }

  func updateNSView(_ nsView: NSTextView, context: Context) {
    nsView.textStorage?.setAttributedString(text)
  }
}

我想将其垂直居中,因此我使用了 VStack 以及上方和下方的 Spacers。 我想在其周围留下与窗口大小成比例的左右边距,因此我将其包装在 GeometryReaderframe() 中。

struct ContentView: View {
  func textView() -> some View {
    let text = """
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod \
      tempor incididunt ut labore et dolore magna aliqua.
      """

    // Note: real application has more complex text than this, *not* using
    // NSAttributedString isn't really an option, at least till SwiftUI has
    // proper rich text support.

    let size: CGFloat = 18
    let font = NSFont(name: "LeagueSpartan-Bold", size: size) 
    let attrString = NSAttributedString(
      string: text,
      attributes: [ .foregroundColor: NSColor.systemYellow,
                    .font: font ?? NSFont.systemFont(ofSize: size) ])
    return TextView(text: attrString)
  }

  var body: some View {
    let textView: some View = self.textView()
    return ZStack {
      // use ZStack to provide window background color
      Color(NSColor.systemTeal)
      VStack {
        Spacer()
        GeometryReader { m2 in
          textView.frame(width: m2.size.width / 1.618)
        }
        Spacer()
      }
    }
  }
}

水平框架工作正常,但垂直间距根本不起作用:

initial state

(初始状态)

调整窗口大小会产生恶作剧:

resize from bottom

(从底部调整大小)

resize from bottom to top, then down again

(从下到上调整大小,然后再次向下调整)

哦,预览完全是香蕉:

Preview

如果我将自定义 TextView 替换为 SwiftUI native Text,则布局工作正常,这表明问题出在 > TextView 。 (另请注意,默认窗口尺寸较小。)

native Text

NSTextView 的大小可能未正确设置。如果我将 nsView.sizeToFit() 添加到 updateNSView() 中:

    func updateNSView(_ nsView: NSTextView, context: Context) {
        nsView.textStorage?.setAttributedString(text)
        nsView.sizeToFit()
    }

这使我获得较小的默认窗口大小,并在我上下调整大小时阻止文本弹到窗口底部,但文本仍然固定在窗口顶部附近,预览仍然损坏,从底部调整大小仍然会使 NSTextView 暂时填充窗口的大部分高度。

我尝试摆弄的其他东西:isVerticallyResizingsetContentCompressionResistancePriorityautoresizingMasktranslatesAutoresizingMaskIntoConstraintsinvalidateIntrinsicContentSize。这些似乎都没有产生任何明显的区别。

似乎我想要的是在包含的 SwiftUI View 调整大小时更新 NSTextView 大小,但似乎没有任何明显的方法可以做到这一点,而且我可能是错的.

最佳答案

如果您只需要显示 NSAttributedString,据我了解,那么基于 NSTextField 的方法(如下所示)更合适,因为 NSTextView 没有默认的内部布局,需要显式的外部框架。

demo

这里是修改后的可表示,ContentView不需要修改。

struct TextView: NSViewRepresentable {
  typealias NSViewType = NSTextField

  var text: NSAttributedString

  func makeNSView(context: Context) -> NSTextField {
    let view = NSTextField()
    // set background color to show view bounds
    view.backgroundColor = NSColor.systemBlue
    view.drawsBackground = true
    view.isEditable = false
    view.isSelectable = false
    view.lineBreakMode = .byWordWrapping
    view.maximumNumberOfLines = 0
    view.translatesAutoresizingMaskIntoConstraints = false
    view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
    view.setContentCompressionResistancePriority(.required, for: .vertical)
    return view
  }

  func updateNSView(_ nsView: NSTextField, context: Context) {
    nsView.attributedStringValue = text
  }
}

关于macos - 如何使用 NSViewRepresentable 将 NSTextView 在 SwiftUI View 中垂直居中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61090854/

相关文章:

swift - 从本地存储加载 UIImages 到 collectionView 非常慢

objective-c - NSPopUpButton : multiple values & selectedIndex binding

swift - ScrollView + NavigationView 动画故障 SwiftUI

swift - 核心数据地震演示在预览中崩溃

cocoa - NSTextView 像 NSTextField 一样结束编辑操作

python - 在 Mac OS X 上将 Python3 与 CMake 链接起来

cocoa - 准备 Mac 应用程序以上传到 App Store

swift - 如何访问 SwiftUI Canvas 中的像素数据

objective-c - 以编程方式创建 NSTextView?

ios - NSTextView 在使用不同的 NSParagraphStyles 更改属性时更新速度太慢