美文网首页Mac OS Xcode牛叉的demo学无止境
iOS 小说阅读器APP 仿追书神器

iOS 小说阅读器APP 仿追书神器

作者: 尛焱 | 来源:发表于2016-12-25 15:19 被阅读3387次

    最近正好有空,花两周多写了个基本的小说阅读器,仿照追书神器,数据源和UI都是抓追书神器,实现了书籍搜索、排行榜、自动缓存、下载等功能;最后会给出github链接,欢迎star,交流,参考学习...
    下面整理一下开发中遇到的一些问题:

    1. UIPageViewController
      UIPageViewControllerUIPageViewControllerTransitionStylePageCurl模式没有什么问题,在UIPageViewControllerTransitionStyleScroll模式下,第一次向后滑动时也会响应获取前一页的方法,这个需要注意一下;然后更换章节的时候,调用setViewControllers:direction:animated:completion:方法,这时候UIPageViewController没有清空其内部缓存,它认为已经知道前/后一个页面的存在,不会调用dataSource的代理方法,这时候会导致章节错误;现在的处理方法如下:
         __weak typeof(self) wself = self;
        [_pageViewController setViewControllers:@[[self readPageViewWithChapter:_chapter page:_page]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished) {
            if (finished && !wself.isPageCurlStyle) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [wself.pageViewController setViewControllers:@[[wself readPageViewWithChapter:wself.chapter page:wself.page]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
                });
            }
        }];
    

    网上有文章说这样处理可能会crash,但是现在没有测试到,而且他的是网易新闻那种,谁试用了会crash的话可以联系我(主要这种解决方式简单,不然自己撸个轮子感觉太麻烦了);

    1. 小说分页
      分页主要采用CoreText中的两个方法:CTFramesetterCreateFrameCTFrameGetVisibleStringRange,具体参数和作用方法里都有介绍;代码如下:
    - (void)pagingWithBounds:(CGRect)bounds {
        _pageArr = @[].mutableCopy;
        YReaderSettings *settings = [YReaderSettings shareReaderSettings];
        NSString *content = settings.isTraditional ? self.traditionalStr : self.body;
        NSMutableAttributedString *attr = [[NSMutableAttributedString  alloc] initWithString:content attributes:settings.readerAttributes];
        CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) attr);
        CGPathRef path = CGPathCreateWithRect(bounds, NULL);
        CFRange range = CFRangeMake(0, 0);
        NSUInteger rangeOffset = 0;
        do {
            CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(rangeOffset, 0), path, NULL);
            range = CTFrameGetVisibleStringRange(frame);
            rangeOffset += range.length;
            [_pageArr addObject:@(range.location)];
            if (frame) {
                CFRelease(frame);
            }
        } while (range.location + range.length < attr.length);
        if (path) {
            CFRelease(path);
        }
        if (frameSetter) {
            CFRelease(frameSetter);
        }
        _pageCount = _pageArr.count;
        _attributedString = attr;
    }
    

    这里一个主要问题是实际显示如果和计算分页时的CGRect相同,可能会少显示一行,处理为程序中显示的Rect会比计算时高度增加一点,防止由于行高或者CTFrameGetVisibleStringRange计算与实际显示之间的误差。

    3.获取电池电量
    [[UIDevice currentDevice] batteryLevel]获取电池电量不准,替代方法如下:

    - (double)getCurrentBatteryLevel {
        UIApplication *app = [UIApplication sharedApplication];
        if (app.applicationState == UIApplicationStateActive || app.applicationState==UIApplicationStateInactive) {
            Ivar ivar = class_getInstanceVariable([app class],"_statusBar");
            id status  = object_getIvar(app, ivar);
            for (id aview in [status subviews]) {
                int batteryLevel = 0;
                for (id bview in [aview subviews]) {
                    if ([NSStringFromClass([bview class]) caseInsensitiveCompare:@"UIStatusBarBatteryItemView"] == NSOrderedSame) {
                    
                        Ivar ivar=  class_getInstanceVariable([bview class],"_capacity");
                        if (ivar) {
                            batteryLevel = ((int (*)(id, Ivar))object_getIvar)(bview, ivar);
                            NSLog(@"电池电量:%zi %%",batteryLevel);
                            if (batteryLevel > 0 && batteryLevel <= 100) {
                                return batteryLevel/100.0;
                            }
                        }
                    }
                }
            }
        }
        return 0;
    }
    

    4.简体转繁体
    这里的方法比较麻烦,拿到所有简体和繁体的文字,找出要替换文字在简体中的位置,用繁体中对应位置的文字一一替换,不知道谁有没有更好的方法;

    - (NSString *)transformToTraditionalWith:(NSString *)string {
        NSMutableString *mutableStr = string.mutableCopy;
        NSInteger length = [string length];
        for (NSInteger i = 0; i< length; i++) {
            NSString *str = [string substringWithRange:NSMakeRange(i, 1)];
            NSRange gbRange = [self.simplifiedStr rangeOfString:str];
            if(gbRange.location != NSNotFound) {
                NSString *tString = [self.traditionalStr substringWithRange:gbRange];
                [mutableStr replaceCharactersInRange:NSMakeRange(i, 1) withString:tString];
            }
        }
        return mutableStr.copy;
    }
    

    5.其他功能

    首页 书籍详情 阅读设置等
    本来准备GIF图,但是简书只能上传5M以下文件,详细功能可下载GitHub源码看:
    项目地址:https://github.com/yanxuewen/YReaderDemo

    相关文章

      网友评论

      • cbd0e9016051:您好, 最近开发一个小说APP,看您的源码看的很懵懂,能说一下翻页阅读地方的实现思路吗?qq: 2382890750
      • 51aa90fc67ff:楼主 查看小说api接口失效了吗?返回都是没数据:flushed:
        尛焱:@ryan_ryan 失效了,别人接口加密了
      • 楚简约:问下这个能完美支持txt、PDF、epub吗
      • d196b1f16b21:看源码。。。看不太懂逻辑能详细介绍下吗翻页那部分
      • 小沛2016:无敌
      • 程序员LesterXu:楼主,大赞啊!最近刚好在做一款读书软件,正好可以用上,太谢谢了
      • 狐狸落雨:大神 有简化的demo嘛 0.0 最近在做这一块的东西 你这个demo 东西太多 看不太懂 只要有这个阅读效果的demo就行 0.0
      • SAW_:666666
      • 斯莫白:可以下载这个app吗
      • 53ddec9b650e:demo打不开,JSPatch找不到。
        尛焱:@53ddec9b650e 自己pod 一下吧
      • 暴走的码农:大神你好屌
        尛焱:@暴走的码农 简信
        暴走的码农:大神求认识,求➕QQ
        尛焱:@暴走的码农 菜鸟:joy:
      • 巫师学徒:写的很不错 希望作者添加自动阅读和翻页背面的相关代码 会持续关注
      • 一只霸天犬v:请问支持哪些格式的电子书啊
      • 柳骏:那个bug解决了?
        尛焱:@柳骏 用一个笨方法解决了

      本文标题:iOS 小说阅读器APP 仿追书神器

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