Text Kit

参考、有demo:https://www.objc.io/issues/5-ios7/getting-to-know-textkit/

Snip20180524_2.png

793272-ee22aaffcffc223e.png
Snip20180524_3.png

Snip20180524_1.png

NSTextContainer、NSLayoutManager、NSTextStorage及其相互关系:


Snip20180524_4.png
  • NSTextStorage保存并管理UITextView要展示的文字内容,该类是NSMutableAttributedString的子类,由于可以灵活地往文字添加或修改属性,所以非常适用于保存并修改文字属性。
  • NSLayoutManager用于管理NSTextStorage其中的文字内容的排版布局。
  • NSTextContainer则定义了一个矩形区域用于存放已经进行了排版并设置好属性的文字。

Glyph 字型

  • Glyph = Character + font
  • CGGlyph
  • Glyph由NSLayoutManager控制

通过Glyph可以准确定位文字在视图中的位置,所以例如下划线、文字背景色等都是通过Glyph实现的。


Snip20180526_3.png

分页显示

用两个TextView显示NSTextContainer,系统会自动处理好文字的显示


Snip20180526_1.png

对link作处理

Snip20180526_2.png
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str
{
    // Normal replace
    [_imp replaceCharactersInRange:range withString:str];
    [self edited:NSTextStorageEditedCharacters range:range changeInLength:(NSInteger)str.length - (NSInteger)range.length];
    
    
    
    // Regular expression matching all iWords -- first character i, followed by an uppercase alphabetic character, followed by at least one other character. Matches words like iPod, iPhone, etc.
    static NSDataDetector *linkDetector;
    linkDetector = linkDetector ?: [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink error:NULL];
    
    // Clear text color of edited range
    NSRange paragaphRange = [self.string paragraphRangeForRange: NSMakeRange(range.location, str.length)];
    [self removeAttribute:NSLinkAttributeName range:paragaphRange];
    [self removeAttribute:NSBackgroundColorAttributeName range:paragaphRange];
    [self removeAttribute:NSUnderlineStyleAttributeName range:paragaphRange];
    
    // Find all iWords in range
    [linkDetector enumerateMatchesInString:self.string options:0 range:paragaphRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        // Add red highlight color
        [self addAttribute:NSLinkAttributeName value:result.URL range:result.range];
        [self addAttribute:NSBackgroundColorAttributeName value:[UIColor yellowColor] range:result.range];
        [self addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:result.range];
    }];
}

代码示例

//
//  ViewController.m
//  safeArea
//
//  Created by liboxiang on 2018/4/25.
//  Copyright © 2018年 liboxiang. All rights reserved.
//

#import "ViewController.h"
#import "SecondViewController.h"
#import "TextStorage.h"

@interface ViewController ()

@property (strong, nonatomic) NSTextStorage *textStorage;
@property (strong, nonatomic) UITextView *textView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIButton *pushButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 70, 80, 35)];
    [pushButton setTitle:@"push" forState:UIControlStateNormal];
    [pushButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:pushButton];
    self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    
    [self setupTextView];
}

- (void)setupTextView
{
    CGRect textViewRect = CGRectInset(self.view.bounds,10.0,150.0);
    
    // NSTextContainer
    NSTextContainer * container = [[NSTextContainer alloc] initWithSize:CGSizeMake(textViewRect.size.width,CGFLOAT_MAX)]; // iOS 7.0中的新增内容
    container.widthTracksTextView = YES; //控制当其文本视图被调整大小时,接收是否调整其边界矩形的宽度
//设置贝塞尔曲线,文字会绕开曲线包围位置
    UIBezierPath *exclusion = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 50, 30)];
    container.exclusionPaths = @[exclusion];
    
    // NSLayoutManager
    NSLayoutManager * layoutManager = [[NSLayoutManager alloc] init]; // iOS 7.0中的新增内容
    [layoutManager addTextContainer:container];
    
    
    // NSTextStorage子类
    self.textStorage = [[NSTextStorage alloc] initWithString:@"Alice alsjf lasjdflk aslfkjal; asldfjalsdfj alsdfjals;dfk sdnvlxdnv asldfkjalsdk  alsdjflasdf as;fj asdf aslfjals dfas;ldfkjals flasdfjldksjl.dsa jfkladjsf   Alice alsdfjklk Rabbit"]; // iOS 7.0中的新增内容
    [self.textStorage addLayoutManager:layoutManager];
    
    // UITextView
    UITextView * newTextView = [[UITextView alloc] initWithFrame:textViewRect textContainer:container];
    newTextView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    newTextView.scrollEnabled = YES;
    newTextView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
    // newTextView.editable = NO;
    newTextView.font = [UIFont fontWithName:[UIFont familyNames][2] size:18.0];
    newTextView.dataDetectorTypes = UIDataDetectorTypeAll;
    self.textView = newTextView;
    [self.view addSubview:self.textView];
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(touchesBegan:)];
    [_textView addGestureRecognizer:tap];
}

- (void)buttonAction
{
//修改文字和文字属性
    [_textStorage beginEditing];
    NSDictionary *attrsDic = @{NSTextEffectAttributeName: NSTextEffectLetterpressStyle};
    UIKIT_EXTERN NSString *const NSTextEffectAttributeName NS_AVAILABLE_IOS(7_0);          // NSString, default nil: no text effect
    NSMutableAttributedString *mutableAttrString = [[NSMutableAttributedString alloc] initWithString:@"Letterpress" attributes:attrsDic];
    NSAttributedString *appendAttrString = [[NSAttributedString alloc] initWithString:@" Append:Letterpress"];
    [mutableAttrString appendAttributedString:appendAttrString];
    [_textStorage setAttributedString:mutableAttrString];
    [_textStorage endEditing];
}

- (void)touchesBegan:(UITapGestureRecognizer *)sender {
//获取点击的字体
    if (self.textView.isFirstResponder) {
        return;
    }
    
        CGPoint touchPoint = [sender locationInView:self.textView];
        NSUInteger charIndex = [self.textView.layoutManager
                                characterIndexForPoint:touchPoint
                                inTextContainer:self.textView.textContainer
                                fractionOfDistanceBetweenInsertionPoints:0];
    NSLog(@"%@",[_textView.text substringWithRange:NSMakeRange(charIndex, 1)]);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

创建NSTextStorage子类

必须重写一下四个方法

 -string
 -attributesAtIndex:effectiveRange:
 -replaceCharactersInRange:withString:
 -setAttributes:range:

通知

NSTextStorageWillProcessEditingNotification

UIContentSizeCategoryDidChangeNotification
这是监听系统字体改变的,如果设置了监听,则当在手机设置里面修改字体大小的时候可以接收到消息。

你可能感兴趣的:(Text Kit)