【问题标题】:How do I vertically center an NSTextView in a SwiftUI view with NSViewRepresentable?如何使用 NSViewRepresentable 在 SwiftUI 视图中垂直居中 NSTextView?
【发布时间】:2020-04-07 23:11:26
【问题描述】:

我有一个简单的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)
  }
}

我想让它垂直居中,所以我在上面和下面使用VStackSpacers。 我想在它周围留下与窗口大小成比例的左右边距,所以我将它包裹在 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()
      }
    }
  }
}

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

(初始状态)

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

(从底部调整大小)

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

哦,预览完全是香蕉:

如果我用SwiftUI 本机Text 替换我的自定义TextView,布局工作正常,这表明问题出在TextView。 (另请注意,默认窗口大小更小。)

NSTextView 的大小似乎没有正确设置。如果我将nsView.sizeToFit() 添加到updateNSView()

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

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

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

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

【问题讨论】:

    标签: macos swiftui nstextview


    【解决方案1】:

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

    这里修改可表示,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
      }
    }
    

    【讨论】:

    • 这行得通。奇怪的是,它仍然没有以我为中心,但在 ContentViewGeometryReader 中添加一个 HStack 可以解决此问题。
    • 为了获得我想要的外观,我还必须设置view.isBezeled = false
    猜你喜欢
    • 2021-12-25
    • 2020-04-19
    • 2020-01-05
    • 2019-03-03
    • 2020-01-27
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多