由于Xcode 6仍然有很多Swift漏洞,我不确定它是一个还是我遗漏了一些东西.我的类采用协议NSLayoutManagerDelegate.但似乎不可能覆盖我需要的方法.我做文件描述:
override func layoutManager(_ aLayoutManager: NSLayoutManager!,
didCompleteLayoutForTextContainer aTextContainer: NSTextContainer!,
atEnd flag: Bool) {
}
Run Code Online (Sandbox Code Playgroud)
但是我在这里得到错误:方法不会覆盖其超类中的任何方法.我该怎么办?
我正在尝试使用Core Text函数绘制文本,其行间距尽可能接近使用NSTextView时的行间距.
以此字体为例:
NSFont *font = [NSFont fontWithName:@"Times New Roman" size:96.0];
Run Code Online (Sandbox Code Playgroud)
如果我在NSTextView中使用它,这个字体的行高是111.0.
NSLayoutManager *lm = [[NSLayoutManager alloc] init];
NSLog(@"%f", [lm defaultLineHeightForFont:font]); // this is 111.0
Run Code Online (Sandbox Code Playgroud)
现在,如果我使用Core Text做同样的事情,结果是110.4(假设您可以通过添加上升,下降和前导来计算线高).
CTFontRef cFont = CTFontCreateWithName(CFSTR("Times New Roman"), 96.0, NULL);
NSLog(@"%f", CTFontGetDescent(cFont) + CTFontGetAscent(cFont) +
CTFontGetLeading(cFont)); // this is 110.390625
Run Code Online (Sandbox Code Playgroud)
这非常接近111.0,但对于某些字体,差异要大得多.例如,对于Helvetica,NSLayoutManager给出115.0而CTFont上升+下降+领先= 96.0.很明显,对于Helvetica,我无法使用上升+下降+导致计算线之间的间距.
所以我想我会使用CTFrame和CTFramesetter来布局几行并从中获取行间距.但这也给出了不同的价值观.
CTFontRef cFont = CTFontCreateWithName(CFSTR("Times New Roman"), 96.0, NULL);
NSDictionary *attrs = [NSDictionary dictionaryWithObject:(id)cFont forKey:(id)kCTFontAttributeName];
NSAttributedString *threeLines = [[NSAttributedString alloc] initWithString:@"abcdefg\nabcdefg\nabcdefg" attributes:attrs];
CTFramesetterRef threeLineFramesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)threeLines);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0.0, …Run Code Online (Sandbox Code Playgroud) 我有一个UIImage包含多个图像帧和一个从动画GIF文件切片的持续时间.如果我将图像加载到UIWebView其中将按预期动画,但我想使用UITextView替代.显而易见的选择是使用带有自定义NSLayoutManger和许多自定义NSAttributedString属性的TextKit 来实现各种绘图效果.我有一个单一的UITextView,我想给一个NSAttributedString包含NSTextAttachments的所有图像我需要内联显示.它工作得很好,除了当我加载其中一个动画时UIImages,它们没有动画通过它们的帧.有关如何实现这一点的任何想法?我想出了一个理论选择:
UIImageView使用动画图像创建s,添加为子视图并调用startAnimating我还没有试过这个,但它相当hacky.我想知道是否有更好的选择.
总结:我想一个动画UIImage内UITextView通过NSTextAttachment内部NSAttributedString而不需要额外的UIImageView对象.你可以忽略这个以前用a做的事实UIWebView.UIImage具有用于设置动画帧的属性(images,duration),我目前已配置.如果我将它分配给UIImageView它动画,如果我将其设置为a NSTextAttachment,则不动画.
我将不胜感激任何反馈.谢谢!
在这个帖子中,Core Text计算iOS中的字母框架,他们能够使用Core Text非常精确地计算每个字形的框架.最终的rects完美地拥抱了实际绘制的字形.
使用NSLayoutManager boundingRectForGlyphRange:inTextContainer:似乎不会返回精确的字形边界框:

返回的rects并没有完全包含更复杂的字体(Zapfino示例):

有没有人知道如何复制上述讨论的结果而不进入iOS 7专用应用程序下的核心文本?
谢谢.
在WWDC 2013的会话220(高级文本布局和带有文本工具包的效果)中,他们明确地说NSLayoutManager可以与创建高级文本动画一起使用NSTextStorage并NSTextContainer创建高级文本动画.他们没怎么说.
我想使用NSLayoutManager/ NSTextStorage/ NSTextContainer来创建自定义文本动画.简单地说,我想为各个字形的大小和位置设置动画,并淡化和解开特定的字形.
似乎没有专门的方法和动画文档,NSLayoutManager我发现的唯一教程就在这里.然而,它展示了如何破解NSLayoutManager动画,而不是如何以它应该使用的方式使用它们(它们CATextLayer为每个单独的字形创建!).
有人能指出我正确的方向吗?我知道如何使用NSLayoutManager/ NSTextStorage/ NSTextContainer来呈现静态文本.一些演示,显示动画文本的原理NSLayoutManager将是完美的.为了让我开始,我可以自己弄清楚细节.
为了支持该UIAccessibilityReadingContent协议,我需要我的UITextView来回答有关其行的问题.这些是我需要实现的协议的方法:
accessibilityLineNumberForPoint: < - 提供坐标,返回行号accessibilityContentForLineNumber: < - 返回给定行的文本accessibilityFrameForLineNumber: < - 给定行号,返回其帧accessibilityPageContent< - 整个文本内容.我有.:)我认为NSLayoutManager可以帮助我,但我对它没有经验.我已经想到了一些(我认为),但仍然需要一些帮助.
Apple有一些示例代码(此处)可以获取文本视图中的行数:
NSLayoutManager *layoutManager = [textView layoutManager];
unsigned numberOfLines, index, numberOfGlyphs =
[layoutManager numberOfGlyphs];
NSRange lineRange;
for (numberOfLines = 0, index = 0; index < numberOfGlyphs; numberOfLines++){
(void) [layoutManager lineFragmentRectForGlyphAtIndex:index
effectiveRange:&lineRange];
index = NSMaxRange(lineRange);
}
Run Code Online (Sandbox Code Playgroud)
我用lineRange上面的数字来计算,我可以使用这个方法计算行数NSLayoutManager:
- (NSRect)boundingRectForGlyphRange:(NSRange)glyphRange inTextContainer:(NSTextContainer *)container
Run Code Online (Sandbox Code Playgroud)
鉴于lineRanges我应该能够计算一个点的行号(通过找到lineRange包含字形索引的行号):
- (NSUInteger)glyphIndexForPoint:(CGPoint)point inTextContainer:(NSTextContainer *)container fractionOfDistanceThroughGlyph:(CGFloat *)partialFraction
Run Code Online (Sandbox Code Playgroud)
剩下的是,如果给出行号,我如何得到一行(作为一个NSString)的内容?
我有一个问题,"boundingRectForGlyphRange"总是返回CGRect.zero"0.0,0.0,0.0,0.0"."boundingRectForGlyphRange"无效.例如,我正在编写触摸UILabel功能的部分文本.我的文字的第一部分是"任何文字",第二部分是"阅读更多".我希望点击识别器仅在我触摸"READ MORE"时才能工作.如果我触摸UILabel上的任何一点,"CGRectContainsPoint"总是返回true,然后调用该动作
这是我的代码:
override func viewDidLoad() {
super.viewDidLoad()
// The full string
let firstPart:NSMutableAttributedString = NSMutableAttributedString(string: "Lorem ipsum dolor set amit ", attributes: [NSFontAttributeName: UIFont.systemFontOfSize(13)])
firstPart.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(),
range: NSRange(location: 0, length: firstPart.length))
info.appendAttributedString(firstPart)
// The "Read More" string that should be touchable
let secondPart:NSMutableAttributedString = NSMutableAttributedString(string: "READ MORE", attributes: [NSFontAttributeName: UIFont.systemFontOfSize(14)])
secondPart.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor(),
range: NSRange(location: 0, length: secondPart.length))
info.appendAttributedString(secondPart)
lblTest.attributedText = info
// Store range of chars we want to detect touches for
moreStringRange = NSMakeRange(firstPart.length, secondPart.length)
print("moreStringRange\(moreStringRange)") …Run Code Online (Sandbox Code Playgroud) 我有一个静态单元格的表视图.一个单元格包含a UITextView并且heightForRowAtIndexPath:是动态计算的,因此单元格总是足够高以容纳文本(该部分在iOS 7下进行了一些工作,实际上,因为它不再可能只是简单地询问textView contentSize).
当我在文本视图中点击开始编辑时,键盘动画到位,tableView上的contentInsets会自动调整以解决此问题(即,iPhone纵向方向的216px底部插入),光标/插入符号变为可见,然后表格视图滚动到另一个位置.它最终看起来像一个反弹.
以下是模拟器中的视频:https://www.dropbox.com/s/htdbb0t7985u6n4/textview-bounce.mov
请注意,插入符号位于键盘上方.我一直在记录表视图contentOffset,我可以看到它滚动到一个很好的值,然后突然"转身"并向后滚动.
奇怪的是,如果我在模拟器中打开慢动画,问题就会消失; 在contentOffset逆转不会发生的事情和工作,我希望(即iOS 6的行为).
以下是动画速度较慢的视频:https://www.dropbox.com/s/nhn7vspx86t4exb/textview-nobounce.mov
实施说明:
boundingRectWithSize:计算表视图高度,调整lineFragmentPadding和任何顶部/底部插入.似乎工作.scrollEnabled== YES 时没有注意到任何不同automaticallyAdjustsScrollViewInsets== YES在AppKit中有没有办法快速测量大量NSString对象(比如一百万)的宽度?我尝试了3种不同的方法:
Count\Mechanism sizeWithAttributes NSAttributedString NSLayoutManager
1000 0.057 0.031 0.007
10000 0.329 0.325 0.064
100000 3.06 3.14 0.689
1000000 29.5 31.3 7.06
NSLayoutManager显然是要走的路,但问题在于
如果你想玩,这是github项目.
cocoa objective-c nslayoutmanager nsattributedstring nstextstorage
我正在尝试实现一个非常简单的文本编辑器,该文本编辑器应可同时NSTextView在macOS和UITextViewiOS上使用。该文本编辑器有一个工具栏按钮“分节符”,每次单击它都会在当前光标位置插入一个新节。一节应为:
在视觉上可识别为一个部分(通过在两个后续部分之间添加视觉分隔符,并可能添加一些垂直空白),
参考。用户应该能够在编辑器中看到所有部分的列表,并且通过单击该列表中的项目,文本视图应立即滚动到该部分的开头。
在另一个问题,我问怎么解决的第一个问题,不幸的是,我还没有发现在这部分的答案,但(即使是一个解决方案,仅在MacOS作品)。
但是,这个问题集中在第二个方面:
如何在我的文本视图中维护所有部分的列表,其中每个部分都能准确地引用相关文本?
此任务的复杂性在于用户可以随时复制和粘贴或简单地编辑文本的任何部分。因此,我无法保留简单的段落编号数组或类似的内容。
我曾经有一个想法是继承NSTextStorage并使用可变属性字符串数组作为其内部存储。然后,我将使用的特殊子类NSTextAttachment并将其用作文本存储中的分节符指示符。问题在于,每当用户编辑文本时,文本视图仅调用以下方法:
func replaceCharacters(in range: NSRange,
with str: String)
Run Code Online (Sandbox Code Playgroud)
和
func setAttributes(_ attrs: [NSAttributedString.Key : Any]?,
range: NSRange)
Run Code Online (Sandbox Code Playgroud)
第一种方法仅传递不带任何属性的纯字符串,第二种方法仅获取属性。这意味着在第一种方法中,我无法确定替换字符是否实际上应该是分节符,因此我无法确定此时在内部文本存储数组中的哪个位置创建新元素。
在第二种方法中,我不知道用户是否实际添加了新文本(在这种情况下,我将不得不在文本存储数组中为每个分节符属性添加一个新元素)还是用户只是更改了现有的某些属性文本(在这种情况下,先前已经创建了新的数组元素)。
我还考虑了在表视图或堆栈视图中使用多个文本视图的想法。但是,这不起作用,因为它将使用户无法选择(和删除)多个后续部分中的文本。
最后,我尝试了子类化NSLayoutManager,但是关于它的文档确实很薄,对我来说似乎是错误的地方。(毕竟,布局经理的职责是文本的布局,而不是跟踪其结构。)
nslayoutmanager ×10
ios ×6
objective-c ×3
textkit ×3
uitextview ×3
cocoa ×2
ios7 ×2
nstextview ×2
swift ×2
uilabel ×2
animation ×1
core-text ×1
glyph ×1
ipad ×1
iphone ×1
macos ×1
uitableview ×1
voiceover ×1