我的最终目标是让用户能够将文本拆分为一个NSTextView或UITextView多个部分,其中两个后续部分通过自定义视图分隔符在视觉上分开(可能,但不一定是水平规则 - 我希望能够调整分离器的视觉外观没有麻烦)。
我需要一个适用于两个平台的解决方案:macOS 和 iOS。
(我的相关问题集中在 macOS 的解决方案上,并且有一个使用NSTextAttachmentCells 在 iOS 上不可用。)
我目前解决这个问题的方法如下:
当用户点击该按钮时,我会创建一个没有文本但带有文本附件的新属性字符串:
let attachment = SectionChangeTextAttachment()
let attachmentString = NSAttributedString(attachment: attachment)
Run Code Online (Sandbox Code Playgroud)
(SectionChangeTextAttachment是NSTextAttachment我创建的自定义子类,以便能够将此分节符附件与其他可能的附件区分开来。)
我将其插入attachmentString到当前光标位置的文本存储中:
textStorage.insert(attachmentString, at: textView.selectedRange().location)
Run Code Online (Sandbox Code Playgroud)我创建了一个自定义NSLayoutManager子类。它的任务是找到类的所有附件,SectionChangeTextAttachment并用分隔符图(或字形?)替换所有出现的地方。这就是问题所在:由于 Apple 有限且部分过时的文档,我无法弄清楚如何执行此操作。
所以我的问题是:
如何让我的布局管理器用比字符/字形占用更多空间的自定义图形(分隔符)替换附件字符(带有特定附件)?
(我猜附件字符没有字形,因此布局管理器没有为它提供任何空间。)
我需要覆盖哪些方法才能使其工作?
(这种方法从一开始就有意义吗?)
nslayoutmanager nsattributedstring nstextattachment ios nstextstorage
Mac OS X上的NSTextContainer有一个方法replaceLayoutManager:用NSLayoutManager的子类替换NSTextView的NSLayoutManager。
不幸的是iOS没有这样的功能。我尝试了这些代码行的组合,但它不断崩溃。
THLayoutManager *layoutManager = [[THLayoutManager alloc] init];
[layoutManager addTextContainer:[self textContainer]];
// [[self textStorage] removeLayoutManager:[self layoutManager]];
//[[self textStorage] addLayoutManager:layoutManager];
[[self textContainer] setLayoutManager:layoutManager];
Run Code Online (Sandbox Code Playgroud)
替换 UITextview 的 NSLayoutManager 的正确步骤是什么?
我想得到UILabel上的tapped字符的索引.我已经将UILabel分类了.在我的awakeFromNib()中我有这个:
layoutManager = NSLayoutManager()
textStorage = NSTextStorage(attributedString: self.attributedText)
textStorage.addLayoutManager(layoutManager)
textContainer = NSTextContainer(size: CGSizeMake(self.frame.size.width, self.frame.size.height))
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = self.numberOfLines
textContainer.lineBreakMode = self.lineBreakMode
textContainer.size = self.frame.size
layoutManager.addTextContainer(textContainer)
Run Code Online (Sandbox Code Playgroud)
这是我想要它的标签的前5个字符的方式,因为我点击第一个字符,在我的touchesEnded我得到一个0的索引:
var touchedCharacterIndex = layoutManager.characterIndexForPoint(touch.locationInView(self), inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
但是当我点击UILabel的前四个字符的任何地方时,我得到4或0,这是不正确的.
谢谢,
更新
根据评论中的建议,我添加了这个:
func updateTextStorage() {
if let attributedText = self.attributedText {
textStorage = NSTextStorage(attributedString: attributedText)
}
textStorage?.addLayoutManager(layoutManager)
textContainer = NSTextContainer(size: CGSizeMake(self.frame.size.width, self.frame.size.height))
textContainer?.lineFragmentPadding = 7
textContainer?.maximumNumberOfLines = self.numberOfLines
textContainer?.lineBreakMode = self.lineBreakMode
textContainer?.size = self.bounds.size
layoutManager.addTextContainer(textContainer!)
layoutManager.textStorage = textStorage
}
Run Code Online (Sandbox Code Playgroud)
我称这种现象layoutSubviews(), …
我在这个问题中学到了 NAlexN 的答案(在 UILabel 的 NSAttributedString 中创建可点击的“链接”?),并自己编写了一个演示。然而,我很不幸地完成了这个演示。这是我的代码:(大家可以直接将以下代码复制到新项目中进行测试)
#import "ViewController.h"
@interface ViewController ()
{
UILabel* label;
NSTextContainer *textContainer;
NSLayoutManager *layoutManager;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[super viewDidLoad];
label=[[UILabel alloc]initWithFrame:CGRectMake(15, 30, 350, 300)];
label.backgroundColor=[UIColor greenColor];
label.userInteractionEnabled = YES;
UITapGestureRecognizer* tap=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTapOnLabel:)];
[tap setNumberOfTapsRequired:1];
[label addGestureRecognizer:tap];
[self.view addSubview:label];
NSMutableAttributedString *attributedString =[[NSMutableAttributedString alloc] initWithString:@"String with a link" attributes:nil];
NSRange linkRange = NSMakeRange(14, 4); // for the word "link" in the string above
NSDictionary *linkAttributes = @{ NSForegroundColorAttributeName …Run Code Online (Sandbox Code Playgroud) 我正在尝试显示不可见的字符,例如 NSTextView 子类中的换行符。像重写 NSLayoutManager 的 drawGlyph 方法这样的常用方法是一个坏主意,因为它太慢并且不能正常工作于多页布局。
\n\n我想要做的是重写 NSLayoutManager 的 setGlyph 方法,以便它将不可见的“\\n”字形替换为“\xc2\xb6”字形,将“ ”替换为“\xe2\x88\x99”。
\n\n它适用于“ ”空格字形,但对新行字符没有影响。
\n\npublic override func setGlyphs(_ glyphs: UnsafePointer<CGGlyph>, properties props: UnsafePointer<NSGlyphProperty>, characterIndexes charIndexes: UnsafePointer<Int>, font aFont: Font, forGlyphRange glyphRange: NSRange) {\n var substring = (self.currentTextStorage.string as NSString).substring(with: glyphRange)\n\n // replace invisible characters with visible\n if PreferencesManager.shared.shouldShowInvisibles == true {\n substring = substring.replacingOccurrences(of: " ", with: "\\u{00B7}")\n substring = substring.replacingOccurrences(of: "\\n", with: "u{00B6}")\n }\n\n // create a CFString\n let stringRef = substring as CFString\n let …Run Code Online (Sandbox Code Playgroud) ios ×3
uilabel ×2
appkit ×1
cocoa ×1
cocoa-touch ×1
ios7 ×1
iphone ×1
objective-c ×1
swift ×1
uitextview ×1