TextKit小记

TextKit介绍

iOS7 introduced a new high-level text-rendering framework called TextKit. TextKit is based on the extremely powerful CoreText rendering engine, and all the Apple-provided text-based controls have been updated to use the TextKit engine.

1. Dynamic Type - 动态类型

动态类型并不是简单地改变字体大小的能力,也改变其他类型的属性:如字体和行间距。确保了文本是可读的。

基本样式:

1
self.subHeadingLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];

iOS7有如下样式:

  • UIFontTextStyleHeadline
  • UIFontTextStyleBody
  • UIFontTextStyleSubheadline
  • UIFontTextStyleFootnote
  • UIFontTextStyleCaption1
  • UIFontTextStyleCaption2

(2015.10.07 补充,iOS9 增加的样式):

  • UIFontTextStyleTitle1
  • UIFontTextStyleTitle1
  • UIFontTextStyleTitle1

响应文本更新:

添加通知

1
2
3
4
5
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(preferredContentSizeChanged:)
name:UIContentSizeCategoryDidChangeNotification
object:nil];

调用 preferredContentSizeChanged: 方法:

1
2
3
- (void)preferredContentSizeChanged:(NSNotification *)notification {
self.textView.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
}

刷新表格:

1
2
3
- (void)preferredContentSizeChanged:(NSNotification *)notification {
[self.tableView reloadData];
}

####凸版效果

添加微妙的阴影和高光的文本给它的深度感 - 就像文本已略有压入画面。

在tableView:cellForRowAtIndexPath: 中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];

Note* note = [self notes][indexPath.row];

UIFont* font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];

UIColor* textColor = [UIColor colorWithRed:0.175f green:0.458f blue:0.831f alpha:1.0f];
NSDictionary *attrs = @{ NSForegroundColorAttributeName : textColor,
NSFontAttributeName : font,
NSTextEffectAttributeName : NSTextEffectLetterpressStyle};

NSAttributedString* attrString = [[NSAttributedString alloc]
initWithString:note.title
attributes:attrs];

cell.textLabel.attributedText = attrString;

return cell;

2. Exclusion paths - 文本环绕

文本定位:

在 viewDidView 中:

1
2
_timeView = [[TimeIndicatorView alloc] initWithDate:_note.timestamp];
[self.view addSubview:_timeView];

定位 _timeView 在右上角:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)viewDidLayoutSubviews {
[self updateTimeIndicatorFrame];
}

- (void)updateTimeIndicatorFrame {
[_timeView updateSize];
_timeView.frame = CGRectOffset(_timeView.frame,
self.view.frame.size.width - _timeView.frame.size.width, 0.0);
}

- (void)preferredContentSizeChanged:(NSNotification *)n {
self.textView.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
[self updateTimeIndicatorFrame];
}

Exclusion paths:

1
- (UIBezierPath *)curvePathWithOrigin:(CGPoint)origin;

定义路径:

1
2
UIBezierPath* exclusionPath = [_timeView curvePathWithOrigin:_timeView.center];
_textView.textContainer.exclusionPaths = @[exclusionPath];

3. Font Descriptors - 字体描述

1、用来修改字体,而不是完全指定一个新的字体,比如用 fontWithName:size:,然后加粗等。

1
2
3
4
5
6
// 拿到字体描述 UIFontTextStyleBody -> UIFontDescriptorTraitBold 将字体描述加粗
// fontDescriptorWithSymbolicTraits: 返回新的字体描述

UIFontDescriptor *bodyFontDesciptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
UIFontDescriptor *boldBodyFontDescriptor = [bodyFontDesciptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
self.boldBodyTextLabel.font = [UIFont fontWithDescriptor:boldBodyFontDescriptor size:0.0];

这个例子是使用字体的加粗,其他的例子如下:

  • UIFontDescriptorTraitItalic
  • UIFontDescriptorTraitExpanded
  • UIFontDescriptorTraitCondensed

2、 创建一个字典的,然后找到匹配要求的字体描述。

1
2
3
4
5
6
// 创建字体描述
UIFontDescriptor *scriptFontDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:
@{UIFontDescriptorFamilyAttribute: @"Zapfino",
UIFontDescriptorSizeAttribute: @15.0}
];
self.scriptTextLabel.font = [UIFont fontWithDescriptor:scriptFontDescriptor size:0.0];

在这里指定字体和大小的属性,也可以使用其他属性,包括:

  • UIFontDescriptorNameAttribute
  • UIFontDescriptorTextStyleAttribute
  • UIFontDescriptorVisbileNameAttribute
  • UIFontDescriptorMatrixAttribute

3. NSTextStorage, NSLayoutManager, NSTextContainer, UITextView:

NSTextStorage 存储要呈现为归因串的文本和通知任何改变文本的内容的 layoutManager。

NSLayoutManager 取得所存储的文本布局,它可以作为程序布局引擎。

NSTextContainer 描述了文本呈现的屏幕的区域的几何形状。每个文本容器通常与相关联的 UITextView ,渲染文本。

1
2
3
4
5
@interface SCViewController () {
NSLayoutManager *_layoutManager;
NSTextStorage *_textStorage;
}
@end

NSTextStorage 继承自 NSMutableAttributedString,管理NSLayoutManager对象,通知他们所有变化的特征或属性,这样他们就可以传递并根据需要重新显示文本。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Import the content into a text storage object
NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@"content" withExtension:@"txt"];
_textStorage = [[NSTextStorage alloc] initWithFileURL:contentURL
options:nil
documentAttributes:NULL
error:NULL];

// 创建layout manager
_layoutManager = [[NSLayoutManager alloc] init];
[_textStorage addLayoutManager:_layoutManager];

// 布局容器
[self layoutTextContainers];

创建 NSTextContainer 区域大小,并添加 text container 的 layout manager :

1
2
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:columnSize];
[_layoutManager addTextContainer:textContainer];

创建 UITextView 展示:

1
2
3
4
5
// And a text view to render it
UITextView *textView = [[UITextView alloc] initWithFrame:textViewFrame
textContainer:textContainer];
textView.scrollEnabled = NO;
[self.scrollView addSubview:textView];

总体来说就是: NSTextStorage add NSLayoutManager

NSLayoutManager add NSTextContainer

UITextView initWith NSTextContainer 。


以上