Mac开发基础13-NSTextView(一)

NSTextView 是 macOS 应用开发中相当强大的多行文本输入控件。它不仅支持文本输入和显示,还支持富文本、文本编辑、布局管理等功能。

常见 API 和基础技巧

初始化 NSTextView

程序化创建

Objective-C
// 创建一个NSScrollView作为NSTextView的容器,因为NSTextView通常需要带滚动条的容器
NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 400, 300)];

// 创建一个NSTextView实例
NSTextView *textView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 400, 300)];

// 设置NSTextView可以编辑和选择
[textView setEditable:YES];
[textView setSelectable:YES];

// 将NSTextView添加到NSScrollView
[scrollView setDocumentView:textView];
Swift
// 创建一个NSScrollView作为NSTextView的容器,因为NSTextView通常需要带滚动条的容器
let scrollView = NSScrollView(frame: NSMakeRect(0, 0, 400, 300))

// 创建一个NSTextView实例
let textView = NSTextView(frame: NSMakeRect(0, 0, 400, 300))

// 设置NSTextView可以编辑和选择
textView.isEditable = true
textView.isSelectable = true

// 将NSTextView添加到NSScrollView
scrollView.documentView = textView

设置和获取文本内容

设置文本

Objective-C
// 设置纯文本
[textView setString:@"Hello, NSTextView!"];

// 设置富文本
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:@"Hello, NSTextView!" attributes:@{NSForegroundColorAttributeName: [NSColor blueColor]}];
[textView.textStorage setAttributedString:attributedText];
Swift
// 设置纯文本
textView.string = "Hello, NSTextView!"

// 设置富文本
let attributedText = NSAttributedString(string: "Hello, NSTextView!", attributes: [.foregroundColor: NSColor.blue])
textView.textStorage?.setAttributedString(attributedText)

获取文本

Objective-C
// 获取纯文本
NSString *plainText = [textView string];

// 获取富文本
NSAttributedString *attributedText = [textView attributedString];
Swift
// 获取纯文本
let plainText = textView.string

// 获取富文本
let attributedText = textView.attributedString()

文本属性和样式

设置文本属性

Objective-C
// 设置文本字体
[textView setFont:[NSFont fontWithName:@"Helvetica" size:14]];

// 设置文本颜色
[textView setTextColor:[NSColor blackColor]];

// 设置文本对齐方式
[textView setAlignment:NSTextAlignmentLeft];
Swift
// 设置文本字体
textView.font = NSFont(name: "Helvetica", size: 14)

// 设置文本颜色
textView.textColor = NSColor.black

// 设置文本对齐方式
textView.alignment = .left

编辑和选择

禁用编辑和选择

Objective-C
// 禁用编辑
[textView setEditable:NO];

// 禁用选择
[textView setSelectable:NO];
Swift
// 禁用编辑
textView.isEditable = false

// 禁用选择
textView.isSelectable = false

行间距和段落样式

设置行间距和段落样式

Objective-C
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:5.0]; // 设置行间距

NSDictionary *attributes = @{NSParagraphStyleAttributeName: paragraphStyle};
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"Hello, NSTextView!" attributes:attributes];

[textView.textStorage setAttributedString:attrString];
Swift
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 5.0 // 设置行间距

let attributes: [NSAttributedString.Key: Any] = [.paragraphStyle: paragraphStyle]
let attrString = NSAttributedString(string: "Hello, NSTextView!", attributes: attributes)

textView.textStorage?.setAttributedString(attrString)

插入和删除文本

插入文本

Objective-C
// 插入文本到末尾
[textView.textStorage appendAttributedString:[[NSAttributedString alloc] initWithString:@" More text"]];
Swift
// 插入文本到末尾
textView.textStorage?.append(NSAttributedString(string: " More text"))

删除文本

Objective-C
// 删除指定范围的文本
NSRange range = NSMakeRange(0, 5);
[textView.textStorage deleteCharactersInRange:range];
Swift
// 删除指定范围的文本
let range = NSRange(location: 0, length: 5)
textView.textStorage?.deleteCharacters(in: range)

粘贴板操作

自定义粘贴板操作

Objective-C
- (void)paste:(id)sender {
    NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
    NSString *pasteString = [pasteboard stringForType:NSPasteboardTypeString];
    
    if ([self isValidInput:pasteString]) {
        [textView insertText:pasteString];
    } else {
        NSBeep();
    }
}

- (BOOL)isValidInput:(NSString *)input {
    // 自定义校验逻辑
    return YES;
}
Swift
override func paste(_ sender: Any?) {
    let pasteboard = NSPasteboard.general
    if let pasteString = pasteboard.string(forType: .string) {
        if isValidInput(pasteString) {
            textView.insertText(pasteString, replacementRange: textView.selectedRange())
        } else {
            NSBeep()
        }
    }
}

func isValidInput(_ input: String) -> Bool {
    // 自定义校验逻辑
    return true
}

深入探讨 NSTextView

1. NSTextView 和 NSTextStorage

NSTextView 是一个视图,它使用 NSTextStorage 来管理其内容。NSTextStorage 是一个特殊的 NSMutableAttributedString,它可以自动通知其内容的更改。

2. 用户交互与编辑行为

用户交互事件

可以通过 NSNotification 获得用户与文本视图互动的通知。

Objective-C
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:NSTextDidChangeNotification object:textView];

- (void)textDidChange:(NSNotification *)notification {
    NSTextView *changedTextView = notification.object;
    NSLog(@"Text changed: %@", changedTextView.string);
}
Swift
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: NSText.didChangeNotification, object: textView)

@objc func textDidChange(_ notification: Notification) {
    if let changedTextView = notification.object as? NSTextView {
        print("Text changed: \(changedTextView.string)")
    }
}

委托方法

通过实现 NSTextViewDelegate,可以对文本编辑行为进行精细控制。

Objective-C
@interface ViewController () <NSTextViewDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    textView.delegate = self;
}

- (void)textDidChange:(NSNotification *)notification {
    NSLog(@"Text did change");
}

- (BOOL)textView:(NSTextView *)textView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(nullable NSString *)replacementString {
    // 可以在这里进行输入校验
    NSLog(@"Replacement string: %@", replacementString);
    return YES;
}

@end
Swift
class ViewController: NSViewController, NSTextViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
    }

    func textDidChange(_ notification: Notification) {
        print("Text did change")
    }

    func textView(_ textView: NSTextView, shouldChangeTextIn affectedCharRange: NSRange, replacementString: String?) -> Bool {
        // 可以在这里进行输入校验
        print("Replacement string: \(replacementString ?? "")")
        return true
    }
}

3. 自动文档保存

NSDocumentNSTextView 的一个重要配套组件,可以用于自动保存文档。

使用 NSDocument 进行自动保存

Objective-C
@implementation MyDocument

- (instancetype)init {
    self = [super init];
    if (self) {
        _textView = [[NSTextView alloc] init];
    }
    return self;
}

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
    // 返回保存文档数据
    return [[_textView string] dataUsingEncoding:NSUTF8StringEncoding];
}

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
    // 读取和加载文档数据
    NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    [_textView setString:content];
    return YES;
}

@end
Swift
class MyDocument: NSDocument {

    var textView: NSTextView = NSTextView()

    override init() {
        super.init()
    }

    override func data(ofType typeName: String) throws -> Data {
        // 返回保存文档数据
        return textView.string.data(using: .utf8) ?? Data()
    }

    override func read(from data: Data, ofType typeName: String) throws {
        // 读取和加载文档数据
        if let content = String(data: data, encoding: .utf8) {
            textView.string = content
        }
    }
}

4. 扩展功能:代码高亮与语法检查

通过自定义 NSTextView,可以实现如代码高亮、语法检查等高级功能。

代码高亮

Objective-C
- (void)highlightSyntax {
    NSString *text = [textView string];
    NSMutableAttributedString *highlightedText = [[NSMutableAttributedString alloc] initWithString:text];

    // 添加高亮逻辑,这里只是简单演示
    NSDictionary *attributes = @{NSForegroundColorAttributeName: [NSColor redColor]};
    [highlightedText setAttributes:attributes range:NSMakeRange(0, text.length)];
    
    [textView.textStorage setAttributedString:highlightedText];
}
Swift
func highlightSyntax() {
    let text = textView.string
    let highlightedText = NSMutableAttributedString(string: text)

    // 添加高亮逻辑,这里只是简单演示
    let attributes: [NSAttributedString.Key: Any] = [.foregroundColor: NSColor.red]
    highlightedText.addAttributes(attributes, range: NSRange(location: 0, length: text.count))
    
    textView.textStorage?.setAttributedString(highlightedText)
}

5. 自动文本排版

NSTextView 结合 NSLayoutManagerNSTextContainer,可以实现复杂的文本排版和布局管理。

自定义布局

Objective-C
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(400, CGFLOAT_MAX)];

[layoutManager addTextContainer:textContainer];
textView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 400, 300) textContainer:textContainer];
[textView setHorizontallyResizable:NO];
Swift
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(containerSize: CGSize(width: 400, height: .greatestFiniteMagnitude))

layoutManager.addTextContainer(textContainer)
textView = NSTextView(frame: NSMakeRect(0, 0, 400, 300), textContainer: textContainer)
textView.isHorizontallyResizable = false
posted @ 2024-08-06 16:20  Mr.陳  阅读(89)  评论(0编辑  收藏  举报