iOS开发项目篇

电子书单个章节

2019-02-26  本文已影响10人  小石头呢

项目源代码
链接:
https://pan.baidu.com/s/1I0HM3bSuqJbvAaI1XVZWeA 密码:2qkc

主要代码:

ViewController.m文件

//
//  ViewController.m
//  电子书单章节
//
//  Created by 许磊 on 2019/2/16.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "ViewController.h"
#import "EBookView.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //设置背景颜色
    self.view.backgroundColor = [UIColor brownColor];
    
    //创建一个电子书
    EBookView *bookview = [[EBookView alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height-20)];
    
    //调取loadData方法获取文本内容
    bookview.text = [self loadData];
    
    //设置字体
    bookview.font = [UIFont systemFontOfSize:16];
    
    //添加
    [self.view addSubview:bookview];
    
}

#pragma mark -------loadData ---------
//加载数据
- (NSString *)loadData{
    //从文件读取数据
    //获取路径
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"登山拜师.txt" ofType:nil];
    //NSLog(@"%@",filePath);
    //返回文件的内容
    //NSString *file = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    //NSLog(@"%@",file);
    return [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
}

@end

EBookView文件

//
//  EBookView.h
//  电子书单章节
//
//  Created by 许磊 on 2019/2/16.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import <UIKit/UIKit.h>

//提供给外部访问的

@interface EBookView : UIView

/**接受外部传递过来的数据*/
@property (nonatomic,copy) NSString *text;

/**设置字体*/
@property (nonatomic,strong) UIFont *font;

/**是否需要动画*/
@property (nonatomic,assign) BOOL animated;

@end



//
//  EBookView.m
//  电子书单章节
//
//  Created by 许磊 on 2019/2/16.
//  Copyright © 2019年 xulei. All rights reserved.
//



#import "EBookView.h"

//不希望给外部访问的方法或者属性就在.m文件里面声明

/**翻页状态*/
typedef enum{
    kAnimationTypeUp,
    kAnimationTypeDown
} kAnimationType;

@interface EBookView ()

/**承载的文本*/
@property (nonatomic,strong) UILabel *label;

/**记录当前页数的索引值*/
@property (nonatomic,assign) NSInteger currentPage;//无需赋值,升级版的int,默认为0

/**保存每一页的范围*/
@property (nonatomic,strong) NSMutableArray *pageRangesArray;

@end

@implementation EBookView

//让这个类来管理电子书的操作和显示

//创建一个类 让一个类继承于UIView
//自定义一个控件 通常都是去重写initWithFrame方法
//在这个方法里面实现视图的布局


//重写initWithFrame方法
-(instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self != nil) {
        //设置label相关信息
        self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
        _label.backgroundColor = [UIColor brownColor];
        _label.numberOfLines = 0;
        _label.font = self.font;
        [self addSubview:_label];
        
        //获取第一页相关信息 显示出来
        //不能在这里做 因为initWithFrame的时候text还没有数据
        
        //初始化数组
        self.pageRangesArray = [NSMutableArray array];
        
        //设置是否有动画
        self.animated = YES;
    }
    return self;
}

//重写set方法
//用atext防止重复
- (void)setText:(NSString *)atext{
    _text = [atext copy];
    
    //显示第一页的内容
    NSRange firstPageRange = [self caculatePageRange:_currentPage];
    self.label.text = [self.text substringWithRange:firstPageRange];
    
}

//重写font的get方法
-(UIFont *)font{
    if (_font == nil) {
        //外部没有设置 给一个默认值
        self.font = [UIFont systemFontOfSize:16];
    }
    return _font;
}

#pragma mark -------caculatePageRange ---------
//计算页数range 计算之前得确保是有数据的
- (NSRange)caculatePageRange:(NSInteger)page{
    //定义一个NSRange结构体用于随时记录每一页的具体位置和长度
    NSRange range = NSMakeRange(0, 0);
    
    //第二页开始 将上一页的range拿出来
    if (page > 0) {
        //取出上一页,并转化为基本类型
        NSValue *rgValue = [self.pageRangesArray objectAtIndex:page-1];
        NSRange preRange = [rgValue rangeValue];
        //记录当前page的起始位置 = 上一页的起始位置 + 上一页的长度
        range.location = preRange.location + preRange.length;
    }
    
    //分割页面
    //每一次都是从需要计算的页面的起始位置开始计算
    for (int i = 0; range.location+range.length < self.text.length; i++) {
        
        //1.不断增加字符 (起始点,长度)NSRange(location length)
        range.length++;
        
        //2.获取当前这个range对应子字符串
        NSString *subString = [self.text substringWithRange:range];
        
        //3.计算subString的size(可以考虑抽出来一个方法)
        CGSize realSize = [subString boundingRectWithSize:CGSizeMake(self.label.frame.size.width, 20000) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.font} context:nil].size;
        
        //4.判断是否超过这个显示的高度
        if (realSize.height > self.label.frame.size.height) {
            //进入了这个if里面,就说明下一页的第一个字符被算进来了
            //让range保存这一页的长度
            range.length--;
            
            //保存这个range
            NSValue *rgValue = [NSValue valueWithRange:range];
            [self.pageRangesArray addObject:rgValue];
            
            return range;
        }
    }
    
    //5.如果剩下的文本高度达不到一页,说明到了最后一页
    if (range.length > 0) {
        
        //保存这个range
        NSValue *rgValue = [NSValue valueWithRange:range];
        [self.pageRangesArray addObject:rgValue];
        
        return range;
    } else {
        //这个else部分完全不会触发,但是不写会报错
        return NSMakeRange(0, 0);
    }
    
}

#pragma mark -------touchesBegan ---------
//触摸事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    //获取UITouch对象
    UITouch *touch = [touches anyObject];
    CGPoint handlocation = [touch locationInView:self];
    
    //判断上一页还是下一页
    if (handlocation.x > self.center.x) {
        //下一页
        
        //判断是否到了最后一页
        NSRange currentPageRange = [[self.pageRangesArray objectAtIndex:_currentPage] rangeValue];
        if (currentPageRange.location+currentPageRange.length < self.text.length) {
            [self changePage:_currentPage+1];
        } else {
            NSLog(@"已经是最后一页了");
        }
    } else {
        //上一页
        
        //判断是否到了第一页
        if (_currentPage > 0) {
            [self changePage:_currentPage-1];
        } else {
            NSLog(@"已经是第一页了");
        }
    }
}

#pragma mark -------changePage ---------
//切换页面
//如果页面已经计算好直接获取 没有再次计算
-(void)changePage:(NSInteger)page{
    
    NSRange range;
    
    //判断页面是否计算好放入数组中
    if (page > self.pageRangesArray.count -1) {
        //需要计算
        range = [self caculatePageRange:page];
        //动画
        if (self.animated) {
            [self animateWithType:kAnimationTypeUp];
        }
    } else {
        //之前已经计算过了 放入数组中了 直接拿出来使用
        range = [[self.pageRangesArray objectAtIndex:page] rangeValue];
        //动画
        if (self.animated) {
            [self animateWithType:kAnimationTypeDown];
        }
    }
    
    //确认当前页数
    self.currentPage = page;
    
    //显示页面内容
    self.label.text = [self.text substringWithRange:range];
}

#pragma mark -------animateWithType ---------
//动画
-(void)animateWithType:(kAnimationType)type{
    //开始动画
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1];
    if (type == kAnimationTypeUp) {
        [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self cache:NO];
    } else {
        [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self cache:NO];
    }
    //结束动画
    [UIView commitAnimations];
}


@end
运行结果

附一:遇到的困难

解决方法: 在Targets -> Build Phases -> Copy Bundle Resources里面导入资源文件,运行项目

示意图

附二:个人改进点

上一篇下一篇

猜你喜欢

热点阅读