NSTextField - 根据内容大小自动调整大小 - 最多显示 5 行

问题描述 投票:0回答:1

我目前的目标是:

  • 窗口底部显示的TextField
  • TextField 覆盖窗口内容(显示在内容上方)
  • TextField 包裹在 ScrollView 中以具有滚动文本的能力
  • ScrollView
    的内容高度必须最多为 5 行文本。如果
    TextField
    的内容大小等于 5 行或超过 5 行 - ScrollView 的高度必须为 5 行,用户必须能够上下滚动文本
    
    
  • 所以我正在尝试做以下事情:

当文本字段中没有文本或有 1 行文本时:

当文本字段中的文本 >= 5 行时:

但目前它有一个静态高度

SwiftUI 内容视图:

TextField

import Combine
import SwiftUI

@available(macOS 12.0, *)
struct ContentView: View {
    @State var text: String = textSample
    
    var body: some View {
        ZStack {
            VStack{
                Spacer()
                
                Text("Hello")
                
                Spacer()
            }
            
            VStack {
                Spacer()
                
                DescriptionTextField(text: $text)
                    .padding(EdgeInsets(top: 3, leading: 3, bottom: 6, trailing: 3) )
                    .background(Color.green)
            }
        }
        .frame(minWidth: 450, minHeight: 300)
    }
}

let textSample =
"""
hello 1
hello 2
hello 3
hello 4
hello 5
hello 6
hello 7
hello 8
"""

swift macos swiftui layout nstextfield
1个回答
0
投票

import Foundation import SwiftUI import AppKit struct DescriptionTextField: NSViewRepresentable { @Binding var text: String var isEditable: Bool = true var font: NSFont? = .systemFont(ofSize: 17, weight: .regular) var onEditingChanged: () -> Void = { } var onCommit : () -> Void = { } var onTextChange : (String) -> Void = { _ in } func makeCoordinator() -> Coordinator { Coordinator(self) } func makeNSView(context: Context) -> CustomTextView { let textView = CustomTextView(text: text, isEditable: isEditable, font: font) textView.delegate = context.coordinator return textView } func updateNSView(_ view: CustomTextView, context: Context) { view.text = text view.selectedRanges = context.coordinator.selectedRanges } } extension DescriptionTextField { class Coordinator: NSObject, NSTextViewDelegate { var parent: DescriptionTextField var selectedRanges: [NSValue] = [] init(_ parent: DescriptionTextField) { self.parent = parent } func textDidBeginEditing(_ notification: Notification) { guard let textView = notification.object as? NSTextView else { return } self.parent.text = textView.string self.parent.onEditingChanged() } func textDidChange(_ notification: Notification) { guard let textView = notification.object as? NSTextView else { return } self.parent.text = textView.string self.selectedRanges = textView.selectedRanges } func textDidEndEditing(_ notification: Notification) { guard let textView = notification.object as? NSTextView else { return } self.parent.text = textView.string self.parent.onCommit() } } } // MARK: - CustomTextView final class CustomTextView: NSView { private var isEditable: Bool private var font: NSFont? weak var delegate: NSTextViewDelegate? var text: String { didSet { textView.string = text } } var selectedRanges: [NSValue] = [] { didSet { guard selectedRanges.count > 0 else { return } textView.selectedRanges = selectedRanges } } private lazy var scrollView: NSScrollView = { let scrollView = NSScrollView() scrollView.drawsBackground = false scrollView.borderType = .noBorder scrollView.hasVerticalScroller = true scrollView.hasHorizontalRuler = false scrollView.autoresizingMask = [.width, .height] scrollView.translatesAutoresizingMaskIntoConstraints = false return scrollView }() private lazy var textView: NSTextView = { let contentSize = scrollView.contentSize let textStorage = NSTextStorage() let layoutManager = NSLayoutManager() textStorage.addLayoutManager(layoutManager) let textContainer = NSTextContainer(containerSize: scrollView.frame.size) textContainer.widthTracksTextView = true textContainer.containerSize = NSSize( width: contentSize.width, height: CGFloat.greatestFiniteMagnitude ) layoutManager.addTextContainer(textContainer) let textView = NSTextView(frame: .zero, textContainer: textContainer) textView.autoresizingMask = .width textView.backgroundColor = NSColor.clear textView.delegate = self.delegate textView.drawsBackground = true textView.font = self.font textView.isEditable = self.isEditable textView.isHorizontallyResizable = false textView.isVerticallyResizable = true textView.maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) textView.minSize = NSSize(width: 0, height: contentSize.height) textView.textColor = NSColor.labelColor textView.allowsUndo = true textView.isRichText = true return textView } () // MARK: - Init init(text: String, isEditable: Bool, font: NSFont?) { self.font = font self.isEditable = isEditable self.text = text super.init(frame: .zero) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Life cycle override func viewWillDraw() { super.viewWillDraw() setupScrollViewConstraints() scrollView.documentView = textView } private func setupScrollViewConstraints() { scrollView.translatesAutoresizingMaskIntoConstraints = false addSubview(scrollView) refreshScrollViewConstrains() } func refreshScrollViewConstrains() { let finalHeight = min(textView.contentSize.height, font!.pointSize * 6) NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(lessThanOrEqualTo: topAnchor), scrollView.trailingAnchor.constraint(equalTo: trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: bottomAnchor), scrollView.leadingAnchor.constraint(equalTo: leadingAnchor), scrollView.heightAnchor.constraint(lessThanOrEqualToConstant: finalHeight) ]) scrollView.needsUpdateConstraints = true } } extension NSTextView { var contentSize: CGSize { get { guard let layoutManager = layoutManager, let textContainer = textContainer else { print("textView no layoutManager or textContainer") return .zero } layoutManager.ensureLayout(for: textContainer) return layoutManager.usedRect(for: textContainer).size } } }

 的高度应自动适应 
ScrollView
 中的文本,最大高度对应于 5 行,这意味着需要计算文本的高度(您在 
NSTextView
中做到了)并根据该值动态设置
refreshScrollViewConstrains()
的高度。
您需要确保每当 

ScrollView

中的文本发生更改时都会调用您的

refreshScrollViewConstrains()
函数。目前,这种情况还没有发生。尝试通过致电
NSTextView
来更新您的
Coordinator
textDidChange(_:)
:
refreshScrollViewConstrains()

© www.soinside.com 2019 - 2024. All rights reserved.