这个项目已经写了很久了,最近才有空放上来,是我刚开始学习iphone时候的作品,在线小说阅读器。
目的就是用来关联上Data和View,然后
做小说类型的软件,如果想加载处理得更快的话按我的做法是先初始同步加载前三页,然后之后的页面放到后台线程继续加载。
主要使用了UIPageViewController实现。重点和难点在于每一页中文字占据空间的处理。
根据MVC的做法,首先定义了一个文章内容的实体类Data
@interface NovelContent : NSObject
@property(nonatomic,copy) NSString* sid;//章节id
@property(nonatomic,copy) NSString* chapterName;//章节名
@property(nonatomic,retain) NSMutableString* contentString;//当前章节的内容
@property(nonatomic,retain) NSMutableArray* imageArray;//插图连接序列
@property(nonatomic,strong) NSMutableArray* pageOffset;//当前章节偏移量序列
@property(nonatomic) NSInteger totalPageNum;//总页数
@property(nonatomic) unsigned long long contentSize;//内容总容量
//页数偏移量转换操作
-(NSUInteger)getOffsetWithPage:(NSUInteger)pageNum;
-(NSUInteger)getPageWithOffset:(NSUInteger)offset;
//小说内容数据库操作
+(BOOL)creatTableWithDB:(FMDatabase*)dbase;
-(BOOL)insertContentIntoDB;
+(NovelContent*)queryContentWithID:(NSString*)sid;
+(BOOL)deleteAllRecord;
@end
然后把网络下载的章节保存在本地缓存里,根据文章的文件句柄和设定的字体大小计算文章偏移量
- (unsigned long long)indexOfPage:(NSFileHandle *)handle textFont:(UIFont *)font{
unsigned long long offset = [handle offsetInFile];
unsigned long long fileSize = currentNovel.contentSize;
NSUInteger MaxWidth = maxPageWidth, MaxHeigth = maxPageHeight;
BOOL isEndOfFile = NO;
NSUInteger length = 64;//截取长度,这个数越小,计算的偏移量越精准,相对运算速度越慢
NSMutableString *labelStr = [[NSMutableString alloc] init];
do{
for (int j=0; j<3; j++) {
if ((offset+length+j) > fileSize) {
offset = fileSize;
isEndOfFile = YES;
break ;
}
[handle seekToFileOffset:offset];
NSData *data = [handle readDataOfLength:j+length];
if (data) {
NSString *iStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (iStr ) {
NSString *oStr = [NSString stringWithFormat:@"%@%@",labelStr,iStr];
CGSize labelSize=[oStr sizeWithFont:font
constrainedToSize:CGSizeMake(MaxWidth,1000)
lineBreakMode:UILineBreakModeWordWrap];
if (labelSize.height-MaxHeigth > 0 && length != 1) {
//如果初次截取的字符占的size比预设高度大,则截取长度减半再截
if (length <= 5) {
length = 1;
}else {
length = length/(2);
}
}else if (labelSize.height > MaxHeigth && length == 1) {
//截取最后一个字符刚好比预设高度大,判断为文章末尾
offset = [handle offsetInFile]-length-j;
[handle seekToFileOffset:offset];
offset = [self fixOffserWith:handle];
isEndOfFile = YES;
}else if(labelSize.height <= MaxHeigth ) {
[labelStr appendString:iStr];
offset = j+length+offset;
}
break ;
}
}
}
if (offset >= fileSize) {
isEndOfFile = YES;
}
}while (!isEndOfFile);
return offset;
}
NSData *data = [handle readDataOfLength:length];
NSString *content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
注:length为每一页的偏移量
偏移量就相当于当前文章的总页数,每一页要显示的字符串也算出来了,xcode上自带了UIPageViewController的Demo,demo中我们知道UIPageViewController类中每一页相当于一个UIViewController。
参考Demo我在类中加上delegate
@protocol NovelEngineDelegate <NSObject>
@optional
-(void)addNovelContent:(NSString*)content;//添加每一页内容
-(void)threadProgress:(float)num;//反馈当前进程
-(void)loadComplete:(NSUInteger)totalNum;//加载完成提示
@end
根据MVC的做法,定义一个Controller:
@interface ModelControllerEx : NSObject<UIPageViewControllerDataSource,NovelEngineDelegate>
{
UIFont *modelFont; //字体大小(与分页有关)
}
@property (nonatomic,retain) NSMutableArray *pageData;
//根据页数查找视图
-(DataViewController *)viewControllerAtIndex:(NSUInteger)index;
//根据当前视图判断页数
-(NSUInteger)indexOfViewController:(DataViewController *)viewController;
-(id)initWithContent:(NovelContent *)novel font:(UIFont*)font;
-(void)reset;
@end
目的就是用来关联上Data和View,然后
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
DataViewController *startingViewController = [modelController viewControllerAtIndex:0];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
CGRect pageViewRect = self.view.bounds;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
}
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
做小说类型的软件,如果想加载处理得更快的话按我的做法是先初始同步加载前三页,然后之后的页面放到后台线程继续加载。