标签: nslayoutmanager

如何使用 NSLayoutManager 用自定义绘图替换文本附件?

我的最终目标是让用户能够将文本拆分为一个NSTextViewUITextView多个部分,其中两个后续部分通过自定义视图分隔符在视觉上分开(可能,但不一定是水平规则 - 我希望能够调整分离器的视觉外观没有麻烦)。

分节符分隔符的示例屏幕截图

我需要一个适用于两个平台的解决方案:macOS 和 iOS

(我的相关问题集中在 macOS 的解决方案上,并且有一个使用NSTextAttachmentCells 在 iOS 上不可用。)

我目前解决这个问题的方法如下:

  1. 我在窗口的工具栏中有一个按钮来插入分节符。
  2. 当用户点击该按钮时,我会创建一个没有文本但带有文本附件的新属性字符串:

    let attachment = SectionChangeTextAttachment()
    let attachmentString = NSAttributedString(attachment: attachment)
    
    Run Code Online (Sandbox Code Playgroud)

    SectionChangeTextAttachmentNSTextAttachment我创建的自定义子类,以便能够将此分节符附件与其他可能的附件区分开来。)

  3. 我将其插入attachmentString到当前光标位置的文本存储中:

    textStorage.insert(attachmentString, at: textView.selectedRange().location)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 我创建了一个自定义NSLayoutManager子类。它的任务是找到类的所有附件,SectionChangeTextAttachment并用分隔符图(或字形?)替换所有出现的地方。这就是问题所在:由于 Apple 有限且部分过时的文档,我无法弄清楚如何执行此操作。

所以我的问题是:

如何让我的布局管理器用比字符/字形占用更多空间的自定义图形(分隔符)替换附件字符(带有特定附件)?

(我猜附件字符没有字形,因此布局管理器没有为它提供任何空间。)

我需要覆盖哪些方法才能使其工作?

(这种方法从一开始就有意义吗?)

nslayoutmanager nsattributedstring nstextattachment ios nstextstorage

5
推荐指数
0
解决办法
399
查看次数

替换 uitextview 的布局管理器

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 的正确步骤是什么?

nslayoutmanager uitextview ios7

4
推荐指数
1
解决办法
5234
查看次数

从tap中获取UILabel中的角色索引

我想得到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(), …

nslayoutmanager uilabel ios nstextstorage nstextcontainer

4
推荐指数
2
解决办法
2761
查看次数

为什么我无法使用“usedRectForTextContainer”获取textContainer的矩形

我在这个问题中学到了 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)

iphone objective-c nslayoutmanager uilabel ios

4
推荐指数
1
解决办法
1365
查看次数

无论我做什么,NSLayoutManager 都会隐藏新行字符

我正在尝试显示不可见的字符,例如 NSTextView 子类中的换行符。像重写 NSLayoutManager 的 drawGlyph 方法这样的常用方法是一个坏主意,因为它太慢并且不能正常工作于多页布局。

\n\n

我想要做的是重写 NSLayoutManager 的 setGlyph 方法,以便它将不可见的“\\n”字形替换为“\xc2\xb6”字形,将“ ”替换为“\xe2\x88\x99”。

\n\n

它适用于“ ”空格字形,但对新行字符没有影响。

\n\n
public 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)

cocoa cocoa-touch nslayoutmanager appkit swift

4
推荐指数
1
解决办法
2077
查看次数