macOS基础组件之文本编辑器MacEditorTextView
2023-09-11 14:18:48 时间
实战需求
解决基础文本编辑功能
实战代码
// MacEditorView.swift
// mac_preview_demo
//
// Created by cf on 2020/8/16.
//
import Foundation
import Combine
import SwiftUI
struct MacEditorTextView: NSViewRepresentable {
@Binding var text: String
var isEditable: Bool = true
var font: NSFont? = .systemFont(ofSize: 14, 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
}
}
// MARK: - Preview
#if DEBUG
struct MacEditorTextView_Previews: PreviewProvider {
static var previews: some View {
Group {
MacEditorTextView(
text: .constant("{ \n planets { \n name \n }\n}"),
isEditable: true,
font: .userFixedPitchFont(ofSize: 14)
)
.environment(\.colorScheme, .dark)
.previewDisplayName("Dark Mode")
MacEditorTextView(
text: .constant("{ \n planets { \n name \n }\n}"),
isEditable: false
)
.environment(\.colorScheme, .light)
.previewDisplayName("Light Mode")
}
}
}
#endif
// MARK: - Coordinator
extension MacEditorTextView {
class Coordinator: NSObject, NSTextViewDelegate {
var parent: MacEditorTextView
var selectedRanges: [NSValue] = []
init(_ parent: MacEditorTextView) {
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 = true
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.textBackgroundColor
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
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()
setupTextView()
}
func setupScrollViewConstraints() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: topAnchor),
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor)
])
}
func setupTextView() {
scrollView.documentView = textView
}
}
相关文章
- macOS跟linux如何在外网远程ssh连接树莓派
- 移动开发大全之 M1 macOS 上开始使用 .NET MAUI (含完整安装过程)
- Flutter macOS 教程之 03 编写你的第一个macos应用程序 (教程含源码)
- macOS SwiftUI 精品项目之颜色管理App支持弹出查看(教程含源码)
- macOS 开源组件之实现两个照片对比(教程含源码)
- macOS SwiftUI 组件之优雅展示程序开源项目的组件List收起与展开(教程含源码)
- SwiftUI macOS教程之 01 数据持久化@AppStorage 从 UserDefaults 读取和写入值
- macOS SwiftUI 字段和标签组件规范之 02 标签Labels(教程含源码)
- macOS SwiftUI 字段和标签组件规范之 01 组合框Combo Boxes(教程含源码)
- macOS SwiftUI 封装组件之 不确定指示器NSProgressIndicator(教程含源码)
- macOS SwiftUI 进度指示器组件规范之 03 不确定的进度指标 Indeterminate Progress Indicators
- macOS SwiftUI 进度指示器组件规范之 01 进度指标是什么 Progress Indicators
- macOS SwiftUI 封装组件之液位指示器NSLevelIndicator(教程含源码)
- macOS SwiftUI 原生组件之 02 Stepper步进器(教程含源码)
- macOS SwiftUI 原生组件之 01 Slider滑动选择器(教程含源码)
- macOS SwiftUI 封装组件之路径组件实现目录式菜单选择NSPathControl (教程含源码)
- macOS SwiftUI 封装组件之日期选择器图形日历和钟表模式NSDataPicker (教程含源码)
- macOS SwiftUI 封装组件之日期选择器文本模式NSDataPicker (教程含源码)
- macOS SwiftUI 开发教程之数据过滤器ObservableObject(教程含源码)
- macOS SwiftUI 开发教程之延迟显示组件 (教程含源码)
- macOS SwiftUI教程之 Menu菜单组件基础使用(教程含源码)
- Node.js 教程大全之 macOS搭建开发环境(教程含源码)
- macOS SwiftUI 核心组件之网格显示Unicode内容LazyGrid (教程含源码)
- macOS iOS SwiftUI 项目大全之图像处理App基于Metal预定义过滤器过滤图像
- macOS SwiftUI 创建一个完整App需要的代码合集,开发macOS系统赚钱么
- 追新: SwiftUI在iOS 和macOS Beta 4中更新了哪些内容
- 《C语言编程魔法书:基于C11标准》——3.2 macOS系统下搭建C语言编程环境
- macOS安装cocoapods
- word文档都能带毒 可攻击Windows和macOS