Mac開發基礎14-NSTextView(二)
進階使用和技巧
1. 擴展查找和替換功能
可以自定義查找和替換功能,包括高亮查找結果、批量替換等。
查找并高亮
Objective-C
- (void)highlightOccurrencesOfString:(NSString *)searchString {
// 清除之前的高亮效果
[textView.layoutManager removeTemporaryAttribute:NSBackgroundColorAttributeName forCharacterRange:NSMakeRange(0, textView.string.length)];
// 查找并高亮指定字符串
NSString *textViewString = textView.string;
NSRange searchRange = NSMakeRange(0, textViewString.length);
while (searchRange.location < textViewString.length) {
searchRange = [textViewString rangeOfString:searchString options:0 range:searchRange];
if (searchRange.location != NSNotFound) {
// 應用高亮顏色
[textView.layoutManager addTemporaryAttribute:NSBackgroundColorAttributeName value:[NSColor yellowColor] forCharacterRange:searchRange];
searchRange.location += searchRange.length;
searchRange.length = textViewString.length - searchRange.location;
} else {
break;
}
}
}
Swift
func highlightOccurrences(of searchString: String) {
// 清除之前的高亮效果
textView.layoutManager?.removeTemporaryAttribute(.backgroundColor, forCharacterRange: NSRange(location: 0, length: textView.string.utf16.count))
// 查找并高亮指定字符串
let textViewString = textView.string as NSString
var searchRange = NSRange(location: 0, length: textViewString.length)
while let foundRange = textViewString.range(of: searchString, options: [], range: searchRange).toRange() {
// 應用高亮顏色
textView.layoutManager?.addTemporaryAttribute(.backgroundColor, value: NSColor.yellow, forCharacterRange: NSRange(foundRange))
searchRange = NSRange(location: foundRange.upperBound, length: textViewString.length - foundRange.upperBound)
}
}
2. 自動鏈接檢測
NSTextView 具有自動檢測和格式化 URL 的功能,可以自動將 URL 鏈接轉換為可點擊的超鏈接。
啟用自動鏈接檢測
Objective-C
textView.automaticLinkDetectionEnabled = YES;
Swift
textView.isAutomaticLinkDetectionEnabled = true
3. 自定義上下文菜單
可以為 NSTextView 提供自定義的上下文菜單,以增加更多操作選項。
Objective-C
- (NSMenu *)menuForEvent:(NSEvent *)event {
NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Context Menu"];
[menu addItemWithTitle:@"Custom Action" action:@selector(customAction:) keyEquivalent:@""];
[menu addItemWithTitle:@"Another Action" action:@selector(anotherAction:) keyEquivalent:@""];
return menu;
}
- (void)customAction:(id)sender {
NSLog(@"Custom action triggered");
}
- (void)anotherAction:(id)sender {
NSLog(@"Another action triggered");
}
Swift
override func menu(for event: NSEvent) -> NSMenu? {
let menu = NSMenu(title: "Context Menu")
menu.addItem(withTitle: "Custom Action", action: #selector(customAction(_:)), keyEquivalent: "")
menu.addItem(withTitle: "Another Action", action: #selector(anotherAction(_:)), keyEquivalent: "")
return menu
}
@objc func customAction(_ sender: Any?) {
print("Custom action triggered")
}
@objc func anotherAction(_ sender: Any?) {
print("Another action triggered")
}
4. 自定義文本標記(標注)
可以利用 NSTextView 的 NSLayoutManager 和 NSTextStorage 結合 NSAttachment 添加自定義的文本標記或標注。
Objective-C
- (void)addCustomMarkAtRange:(NSRange)range {
// 創建自定義附件標注
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];
[textView.textStorage insertAttributedString:attachmentString atIndex:range.location];
// 添加自定義屬性
[textView.textStorage addAttributes:@{NSForegroundColorAttributeName: [NSColor redColor]} range:range];
}
Swift
func addCustomMark(at range: NSRange) {
// 創建自定義附件標注
let attachment = NSTextAttachment()
let attachmentString = NSAttributedString(attachment: attachment)
textView.textStorage?.insert(attachmentString, at: range.location)
// 添加自定義屬性
textView.textStorage?.addAttributes([.foregroundColor: NSColor.red], range: range)
}
5. 處理空格鍵和回車鍵
可以自定義處理空格鍵和回車鍵,實現更靈活的輸入行為。
Objective-C
- (BOOL)textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector {
if (commandSelector == @selector(insertNewline:)) {
// 自定義處理回車鍵
NSLog(@"Return key pressed");
return YES;
} else if (commandSelector == @selector(insertTab:)) {
// 自定義處理Tab鍵
NSLog(@"Tab key pressed");
return YES;
}
return NO;
}
Swift
override func textView(_ textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if commandSelector == #selector(insertNewline(_:)) {
// 自定義處理回車鍵
print("Return key pressed")
return true
} else if commandSelector == #selector(insertTab(_:)) {
// 自定義處理Tab鍵
print("Tab key pressed")
return true
}
return false
}
常用工具類封裝
下面,我們將封裝一個 NSTextView 的工具類,以更靈活地定制 NSTextView 的行為和功能。
Objective-C
@interface NSTextViewHelper : NSObject
@property (nonatomic, strong) NSTextView *textView;
- (instancetype)initWithTextView:(NSTextView *)textView;
- (void)setPlaceholder:(NSString *)placeholder;
- (void)setTextColor:(NSColor *)color;
- (void)setFont:(NSFont *)font;
- (void)setEditable:(BOOL)editable;
- (void)setSelectable:(BOOL)selectable;
- (void)highlightOccurrencesOfString:(NSString *)searchString;
- (void)addCustomMarkAtRange:(NSRange)range;
- (void)setCustomContextMenu;
@end
@implementation NSTextViewHelper
- (instancetype)initWithTextView:(NSTextView *)textView {
self = [super init];
if (self) {
_textView = textView;
}
return self;
}
- (void)setPlaceholder:(NSString *)placeholder {
if ([_textView isKindOfClass:[NSTextView class]]) {
// 當前沒有直接設置占位符的方法,可以通過擴展創建占位符效果
}
}
- (void)setTextColor:(NSColor *)color {
[_textView setTextColor:color];
}
- (void)setFont:(NSFont *)font {
[_textView setFont:font];
}
- (void)setEditable:(BOOL)editable {
[_textView setEditable:editable];
}
- (void)setSelectable:(BOOL)selectable {
[_textView setSelectable:selectable];
}
- (void)highlightOccurrencesOfString:(NSString *)searchString {
// 清除之前的高亮效果
[_textView.layoutManager removeTemporaryAttribute:NSBackgroundColorAttributeName forCharacterRange:NSMakeRange(0, _textView.string.length)];
// 查找并高亮指定字符串
NSString *textViewString = _textView.string;
NSRange searchRange = NSMakeRange(0, textViewString.length);
while (searchRange.location < textViewString.length) {
searchRange = [textViewString rangeOfString:searchString options:0 range:searchRange];
if (searchRange.location != NSNotFound) {
// 應用高亮顏色
[_textView.layoutManager addTemporaryAttribute:NSBackgroundColorAttributeName value:[NSColor yellowColor] forCharacterRange:searchRange];
searchRange.location += searchRange.length;
searchRange.length = textViewString.length - searchRange.location;
} else {
break;
}
}
}
- (void)addCustomMarkAtRange:(NSRange)range {
// 創建自定義附件標注
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];
[_textView.textStorage insertAttributedString:attachmentString atIndex:range.location];
// 添加自定義屬性
[_textView.textStorage addAttributes:@{NSForegroundColorAttributeName: [NSColor redColor]} range:range];
}
- (void)setCustomContextMenu {
[_textView setMenu:[self customMenu]];
}
- (NSMenu *)customMenu {
NSMenu *menu = [[NSMenu alloc] initWithTitle:@"ContextMenu"];
[menu addItemWithTitle:@"Custom Action" action:@selector(customAction:) keyEquivalent:@""];
[menu addItemWithTitle:@"Another Action" action:@selector(anotherAction:) keyEquivalent:@""];
return menu;
}
- (void)customAction:(id)sender {
NSLog(@"Custom action triggered");
}
- (void)anotherAction:(id)sender {
NSLog(@"Another action triggered");
}
@end
Swift
class NSTextViewHelper {
private weak var textView: NSTextView?
init(textView: NSTextView) {
self.textView = textView
}
func setPlaceholder(_ placeholder: String) {
if let textView = textView {
// 當前沒有直接設置占位符的方法,可以通過擴展創建占位符效果
}
}
func setTextColor(_ color: NSColor) {
textView?.textColor = color
}
func setFont(_ font: NSFont) {
textView?.font = font
}
func setEditable(_ editable: Bool) {
textView?.isEditable = editable
}
func setSelectable(_ selectable: Bool) {
textView?.isSelectable = selectable
}
func highlightOccurrences(of searchString: String) {
guard let textView = textView else { return }
// 清除之前的高亮效果
textView.layoutManager?.removeTemporaryAttribute(.backgroundColor, forCharacterRange: NSRange(location: 0, length: textView.string.utf16.count))
// 查找并高亮指定字符串
let textViewString = textView.string as NSString
var searchRange = NSRange(location: 0, length: textViewString.length)
while let foundRange = textViewString.range(of: searchString, options: [], range: searchRange).toRange() {
// 應用高亮顏色
textView.layoutManager?.addTemporaryAttribute(.backgroundColor, value: NSColor.yellow, forCharacterRange: NSRange(foundRange))
searchRange = NSRange(location: foundRange.upperBound, length: textViewString.length - foundRange.upperBound)
}
}
func addCustomMark(at range: NSRange) {
guard let textView = textView else { return }
// 創建自定義附件標注
let attachment = NSTextAttachment()
let attachmentString = NSAttributedString(attachment: attachment)
textView.textStorage?.insert(attachmentString, at: range.location)
// 添加自定義屬性
textView.textStorage?.addAttributes([.foregroundColor: NSColor.red], range: range)
}
func setCustomContextMenu() {
textView?.menu = customMenu()
}
private func customMenu() -> NSMenu {
let menu = NSMenu(title: "ContextMenu")
menu.addItem(withTitle: "Custom Action", action: #selector(customAction(_:)), keyEquivalent: "")
menu.addItem(withTitle: "Another Action", action: #selector(anotherAction(_:)), keyEquivalent: "")
return menu
}
@objc func customAction(_ sender: Any?) {
print("Custom action triggered")
}
@objc func anotherAction(_ sender: Any?) {
print("Another action triggered")
}
}
使用示例
Objective-C
NSTextView *textView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 400, 300)];
NSTextViewHelper *helper = [[NSTextViewHelper alloc] initWithTextView:textView];
[helper setTextColor:[NSColor blueColor]];
[helper setFont:[NSFont fontWithName:@"Helvetica" size:14]];
[helper setEditable:YES];
[helper highlightOccurrencesOfString:@"NSTextView"];
[helper addCustomMarkAtRange:NSMakeRange(0, 5)];
[helper setCustomContextMenu];
Swift
let textView = NSTextView(frame: NSMakeRect(0, 0, 400, 300))
let helper = NSTextViewHelper(textView: textView)
helper.setTextColor(.blue)
helper.setFont(NSFont(name: "Helvetica", size: 14)!)
helper.setEditable(true)
helper.highlightOccurrences(of: "NSTextView")
helper.addCustomMark(at: NSRange(location: 0, length: 5))
helper.setCustomContextMenu()
將來的你會感謝今天如此努力的你!
版權聲明:本文為博主原創文章,未經博主允許不得轉載。

浙公網安備 33010602011771號