Text Kit

作者: liboxiang | 来源:发表于2018-05-25 09:05 被阅读13次

    参考、有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

          本文链接:https://www.haomeiwen.com/subject/messjftx.html