BookTextView

简介:

BookTextView

 

效果

 

说明

1. 支持富文本

2. 支持自定义view

3. 支持阅读百分比

 

源码

https://github.com/YouXianMing/UI-Component-Collection



//
//  BookTextView.h
//  InTheQuietNight
//
//  Created by YouXianMing on 15/5/18.
//  Copyright (c) 2015年 XianMingYou. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "ExclusionView.h"
#import "ConfigAttributedString.h"

@interface BookTextView : UIView

// 要显示的文本
@property (nonatomic, strong)   NSString       *textString;

// 段落样式的设置
@property (nonatomic, strong)   NSDictionary   *paragraphAttributes;

// 富文本参数数组(ConfigAttributedString对象的数组)
@property (nonatomic, strong)   NSArray        *attributes;

// 计算出的文本的高度
@property (nonatomic, readonly) CGFloat         textHeight;

// 当前文本已读百分比
@property (nonatomic, readonly) CGFloat         currentPercent;

// 存储的图文混排的views
@property (nonatomic, strong)   NSArray        *exclusionViews;

/**
 *  构建出组件(设置完所有参数后再做)
 */
- (void)buildWidgetView;

/**
 *  移动到指定的位置(此方法只有延时执行才有效果,比如延时执行0.01s)
 *
 *  @param position 文本的高度位置
 */
- (void)moveToTextPosition:(CGFloat)position;

/**
 *  移动到指定的百分比(此方法只有延时执行才有效果,比如延时执行0.01s)
 *
 *  @param percent 百分比
 */
- (void)moveToTextPercent:(CGFloat)percent;

@end


//
//  BookTextView.m
//  InTheQuietNight
//
//  Created by YouXianMing on 15/5/18.
//  Copyright (c) 2015年 XianMingYou. All rights reserved.
//

#import "BookTextView.h"

typedef enum : NSUInteger {
    EBOOK_NONE,              // 什么也不做
    EBOOK_CALCULATE_HEIGHT,  // 计算文本高度
} EBookTextViewStatus;

@interface BookTextView ()<UITextViewDelegate> {
    EBookTextViewStatus _bookStatus;
    
    CGFloat             _tmpOffsetY;
    CGFloat             _tmpPercent;
}

@property (nonatomic, strong)   UITextView     *textView;
@property (nonatomic)           CGFloat         textHeight;
@property (nonatomic)           CGFloat         currentPercent;

@end

@implementation BookTextView



- (void)buildWidgetView {
    
    
    // 获取长宽
    CGFloat width  = self.frame.size.width;
    CGFloat height = self.frame.size.height;
    
    
    // 创建文本容器并设置段落样式
    NSTextStorage *storage = [[NSTextStorage alloc] initWithString:self.textString
                                                        attributes:self.paragraphAttributes];
    
    
    // 设置富文本
    for (int count = 0; count < _attributes.count; count++) {
        ConfigAttributedString *oneConfig = _attributes[count];
        [storage addAttribute:oneConfig.attribute
                        value:oneConfig.value
                        range:oneConfig.range];
    }
    
    // 管理器
    NSLayoutManager *layoutManager = [NSLayoutManager new];
    [storage addLayoutManager:layoutManager];
    
    
    // 显示的容器
    NSTextContainer *textContainer = [NSTextContainer new];
    CGSize size                    = CGSizeMake(width, MAXFLOAT);
    textContainer.size             = size;
    [layoutManager addTextContainer:textContainer];
    
    
    // 给TextView添加带有内容和布局的容器
    self.textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, width, height)
                                        textContainer:textContainer];
    self.textView.scrollEnabled                    = YES;
    self.textView.editable                         = NO;
    self.textView.selectable                       = NO;
    self.textView.layer.masksToBounds              = YES;
    self.textView.showsVerticalScrollIndicator     = NO;
    self.textView.delegate                         = self;
    
    
    // 如果有额外的views
    if (self.exclusionViews) {
        
        NSMutableArray *pathArray = [NSMutableArray arrayWithCapacity:_exclusionViews.count];
        
        // 添加view + 添加path
        for (int count = 0; count < _exclusionViews.count; count++) {
            
            // 添加view
            ExclusionView *tmpView = _exclusionViews[count];
            [_textView addSubview:tmpView];
            
            // 添加path
            [pathArray addObject:tmpView.createUIBezierPath];
        }
        
        textContainer.exclusionPaths = pathArray;
    }
    
    // 添加要显示的view
    [self addSubview:self.textView];
    
    
    // 存储文本高度
    [self storeBookHeight];
}

- (void)storeBookHeight {
    
    // 先偏移到文本末尾位置
    _bookStatus = EBOOK_CALCULATE_HEIGHT;
    [UIView setAnimationsEnabled:NO];
    [self.textView scrollRangeToVisible:NSMakeRange([self.textView.text length], 0)];
    [UIView setAnimationsEnabled:YES];
    _bookStatus = EBOOK_NONE;
    
    // 再偏移到文本开头位置
    [UIView setAnimationsEnabled:NO];
    [self.textView scrollRangeToVisible:NSMakeRange(0, 0)];
    [UIView setAnimationsEnabled:YES];
}

- (void)moveToTextPosition:(CGFloat)position {
    [self.textView setContentOffset:CGPointMake(0, position) animated:NO];
}

- (void)moveToTextPercent:(CGFloat)percent {
    
    // 计算出百分比
    CGFloat position = 0.f;
    if (percent >= 0 && percent <= 1) {
        position = percent * _textHeight;
    } else if (percent < 0) {
        position = 0.f;
    } else {
        position = _textHeight;
    }
    
    // 移动到指定的位置
    [self.textView setContentOffset:CGPointMake(0, position) animated:NO];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    // Y轴偏移量
    _tmpOffsetY = scrollView.contentOffset.y;
    if (_bookStatus == EBOOK_NONE) {
        
        
        _tmpPercent = _tmpOffsetY / _textHeight;
        if (_tmpPercent >= 0 && _tmpPercent <= 1) {
            _currentPercent = _tmpPercent;
        } else if (_tmpPercent < 0) {
            _currentPercent = 0.f;
        } else {
            _currentPercent = 1.f;
        }
        
        
        NSLog(@"%f", _currentPercent);
        
        
    } else if (_bookStatus == EBOOK_CALCULATE_HEIGHT) {
        self.textHeight = scrollView.contentOffset.y;
    }
}

@end


目录
相关文章
|
11天前
|
弹性计算 人工智能 安全
对话 | ECS如何构筑企业上云的第一道安全防线
随着中小企业加速上云,数据泄露、网络攻击等安全威胁日益严重。阿里云推出深度访谈栏目,汇聚产品技术专家,探讨云上安全问题及应对策略。首期节目聚焦ECS安全性,提出三道防线:数据安全、网络安全和身份认证与权限管理,确保用户在云端的数据主权和业务稳定。此外,阿里云还推出了“ECS 99套餐”,以高性价比提供全面的安全保障,帮助中小企业安全上云。
201867 14
对话 | ECS如何构筑企业上云的第一道安全防线
|
19天前
|
调度 云计算 芯片
云超算技术跃进,阿里云牵头制定我国首个云超算国家标准
近日,由阿里云联合中国电子技术标准化研究院主导制定的首个云超算国家标准已完成报批,不久后将正式批准发布。标准规定了云超算服务涉及的云计算基础资源、资源管理、运行和调度等方面的技术要求,为云超算服务产品的设计、实现、应用和选型提供指导,为云超算在HPC应用和用户的大范围采用奠定了基础。
179634 22
|
6天前
|
弹性计算 人工智能 安全
|
6天前
|
安全 数据安全/隐私保护
阿里云 SASE 2.0 能力迭代|构建一体化办公数据安全解决方案
阿里云SASE能力全新升级,快速构建数据安全治理与运营体系。
1087 5
|
6天前
|
搜索推荐 物联网 PyTorch
Qwen2.5-7B-Instruct Lora 微调
本教程介绍如何基于Transformers和PEFT框架对Qwen2.5-7B-Instruct模型进行LoRA微调。
388 34
Qwen2.5-7B-Instruct Lora 微调
|
28天前
|
人工智能 自然语言处理 前端开发
从0开始打造一款APP:前端+搭建本机服务,定制暖冬卫衣先到先得
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。
9856 29
|
8天前
|
机器学习/深度学习 人工智能 安全
阿里云先知安全沙龙(武汉站) ——AI赋能软件漏洞检测,机遇, 挑战与展望
本文介绍了漏洞检测的发展历程、现状及未来展望。2023年全球披露的漏洞数量达26447个,同比增长5.2%,其中超过7000个具有利用代码,115个已被广泛利用,涉及多个知名软件和系统。文章探讨了从人工审计到AI技术的应用,强调了数据集质量对模型性能的重要性,并展示了不同检测模型的工作原理与实现方法。此外,还讨论了对抗攻击对模型的影响及提高模型可解释性的多种方法,展望了未来通过任务大模型实现自动化漏洞检测与修复的趋势。
|
13天前
|
机器学习/深度学习 分布式计算 供应链
阿里云先知安全沙龙(上海站) ——大模型基础设施安全攻防
大模型基础设施的安全攻防体系涵盖恶意输入防御和基础设施安全,包括框架、三方库、插件、平台、模型和系统安全。关键漏洞如CVE-2023-6019(Ray框架命令注入)、CVE-2024-5480(PyTorch分布式RPC)及llama.cpp中的多个漏洞,强调了代码安全性的重要性。模型文件安全方面,需防范pickle反序列化等风险,建议使用Safetensors格式。相关实践包括构建供应链漏洞库、智能化漏洞分析和深度检测,确保全方位防护。
|
12天前
|
机器学习/深度学习 人工智能 安全
通义视觉推理大模型QVQ-72B-preview重磅上线
Qwen团队推出了新成员QVQ-72B-preview,这是一个专注于提升视觉推理能力的实验性研究模型。提升了视觉表示的效率和准确性。它在多模态评测集如MMMU、MathVista和MathVision上表现出色,尤其在数学推理任务中取得了显著进步。尽管如此,该模型仍存在一些局限性,仍在学习和完善中。
|
13天前
|
Java Maven
Maven编译报错:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile 解决方案
在执行Maven项目中的`install`命令时,遇到编译插件版本不匹配的错误。具体报错为:`maven-compiler-plugin:3.13.0`要求Maven版本至少为3.6.3。解决方案是将Maven版本升级到3.6.3或降低插件版本。本文详细介绍了如何下载、解压并配置Maven 3.6.3,包括环境变量设置和IDEA中的Maven配置,确保项目顺利编译。
Maven编译报错:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile 解决方案

热门文章

最新文章