(一)iOS开发--电子书模块的设计制作

一.引言

从今天开始,在我的博客上开辟工作项目专栏,来总结记录项目中的开发难点。第一篇记录的是电子书模块。

二.项目需求

一级界面:1.侧滑菜单、2.书籍列表、3.上拉加载

二级界面:1.头部书籍信息、2.书籍简介、3.评价列表、4.评价功能(弹出评价界面)5.底部下载/阅读功能

下载管理界面:1.下载的书籍信息、2.可侧滑删除

阅读界面:1.电子书自适应大小(pdf文件)、2.翻页 、3.记录页

三.总结(后台拿到的测试数据)

1.一级界面

0.0

1.pid为1的为父类,sn进行排序的标志,pid不为1的为子类

*遇到难点:把对应的子类按顺序放到对应的父类下

*解决方法:

NSMutableArray *allArrM = [NSMutableArray array];
            NSMutableArray *childArrM = [NSMutableArray array];
                        for (BookMenuEntity *menu in result) {
                /**
                 *  pid为1的是父类
                 */
                if ([menu.pid isEqual:@1]) {
                    [allArrM addObject:menu];
                }
                else
                    [childArrM addObject:menu];
            }
            /**
             *所有父类+排序
             */
            NSSortDescriptor *allSn = [[NSSortDescriptor alloc] initWithKey:@"sn" ascending:YES];
            NSArray *newAllResult= [allArrM sortedArrayUsingDescriptors:@[allSn]];
            /**
             *所有子类+排序
             */
            NSSortDescriptor *childSn = [[NSSortDescriptor alloc] initWithKey:@"sn" ascending:YES];
            NSArray *childResult= [childArrM sortedArrayUsingDescriptors:@[childSn]];

/*
对应父类有几个,这个可变数组救添加几个数组
*/
            NSMutableArray *newChildResult = [NSMutableArray array];
            for (int i =0; i<newAllResult.count; i++) {
               NSMutableArray *tempArrM = [[NSMutableArray alloc] init];
                [newChildResult addObject:tempArrM];
            }
            int i = 0;
            for (BookMenuEntity *allEntity in newAllResult) {
            /*
子类pid找到对应父类id,对应上就加到对应的数组(相当于加到对应的父类)
*/
                for (BookMenuEntity *childEntity in childResult) {
                    if ([childEntity.pid isEqual:allEntity.ID]) {
                        [newChildResult[i] addObject:childEntity];
                    }
                }
                i++;
            }
            self.allMenuArrM = (NSMutableArray *)newAllResult;
            self.childMenuArrM = newChildResult;
            [self loadMenuData];

1.1

1.1.1

因为要让菜单栏弹出时书籍列表(UICollectionViewController)不可操作,所以加了背景遮罩。

backView = [[UIView alloc] initWithFrame:CGRectMake(0, HEADER, self.view.frame.size.width, self.view.frame.size.height)];
backView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
//加到标签栏上
[self.tabBarController.view addSubview:backView];

 //单击手势,让菜单收起
tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureAction:)];
[tapGesture setNumberOfTapsRequired:1];
[backView addGestureRecognizer:tapGesture];

//为了让菜单的透明度和背景区分,再加个小的背景
view = [[UIView alloc] initWithFrame:CGRectMake(0, HEADER, self.view.frame.size.width/2.5, backView.frame.size.height)];
view.backgroundColor = [UIColor blackColor];
view.alpha = 0.7;
[view addSubview:self.menuTableView];
[self.tabBarController.view addSubview:view];

//没有点击菜单按钮,默认为隐藏
backView.hidden = YES;
view.hidden = YES;

1.1.2

*遇到难点:(1)刚开始时,菜单能正常加到tabBarController.view上,后来push到二级界面后,就不能加到tabBarController.view上(presentd的可以)。

*解决方法:[self.tabBarController.view bringSubviewToFront:backView];

[self.tabBarController.view bringSubviewToFront:view];

1.1.3

菜单点击需求。1??点到谁,谁就变红(表示选中,父类也可以被选中并进行数据加载)2??选中以后,再点击,不进行数据请求3??点击一个父类,其它父类子菜单要全部收起

思路:用一个数组来记录点击选中状态、以及展开闭合状态

/**
 *  1展开,0收起
 */
- (void)loadMenuData {
    //用0代表收起,非0(不一定是1)代表展开,默认都是收起的
    for (int i = 0; i < self.allMenuArrM.count; i++) {
        [self.isExpland addObject:@0];
    }
    if (self.isExpland.count != 0) {
        [self.menuTableView reloadData];
    }
}
#pragma mark 加载菜单栏父类是否被选中的数据
/**
 *  默认第一个父类被选中,1被选中,0没有
 */
- (void)parentChooseAction{
    for (int j=0; j<self.allMenuArrM.count;j++) {
        if (j==0) {
            self.isParentChooseArrM[j] = @1;
        }
        else{
            self.isParentChooseArrM[j] = @0;
        }
    }
}
#pragma mark 加载菜单栏子类是否被选中的数据
/**
 *  1被选中,0没有
 */
- (void)childChoosAction{
    for (int i=0; i<self.childMenuArrM.count; i++) {
        NSMutableArray *arrM = [NSMutableArray array];
        NSMutableArray *arrM2 = self.childMenuArrM[i];
        for (int j=0; j<arrM2.count;j++ ) {
            [arrM addObject:@0];
        }
        [self.childIsChooseArrM addObject:arrM];
    }
}

1.1.4

*遇到难点:(4)因为菜单涉及到很多数据,然后进行多次表格刷新。所以容易出现数组越界

*解决方法:数组为空的时候可能进行了reloadTableView,进行判空操作。尽量减掉重复的reloadTabelView(一开始有四处,后来减到两处)

1.2

1.2.1

*遇到难点:(1)布局collectionViewCell

*解决方法:其它都好弄,但在解决每个cell的间距的时候一定要记住一个属性:minimumInteritemSpacing,不设置它,cell的间距调不了。记得代理UICollectionViewDelegateFlowLayout。

UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
self.collectionView.collectionViewLayout = flowLayout;
flowLayout.minimumInteritemSpacing = 12.5;
[self.collectionView registerClass:[EBookCollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
/*
设置cell的大小
*/
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    return CGSizeMake(90, 202);
}
/*
cell的布局上左下右的屏幕间距
*/
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(10, 12.5, 10,12.5);
}

1.2.2

*遇到难点:(2)书籍介绍需求默认可以显示三行,但是字不够的时候,如何让字顶住左上角

*解决方法:

_introduceLabel.lineBreakMode = NSLineBreakByWordWrapping;//一定要设置这个属性

cell.introduceLabel.text = [NSString stringWithFormat:@"%@\n\n",@"哈哈哈"];

1.2.3

*遇到难点:(3)字体天空蓝

*解决方法:推荐一个好用的第三方颜色器(都调好了)http://download.csdn.net/detail/xj_love/9542251

_introduceLabel.textColor = [UIColor colorWithRed:0/255.0f green:178/255.0f blue:238/255.0f alpha:1.0];

2.二级界面

2.1

2.1.1

!

//注意书籍名标签字的位置1.2.2的难点(2)一样

2.1.2

!

公司用autoLayout进行布局。

*遇到难点:(1)评价内容Label高度自适应(2)cell高度自适应

*解决方法:1??获取文字高度:

/*.h文件*/

@property (strong, nonatomic) IBOutlet NSLayoutConstraint *reviewLabelHeight;

/*.m文件*/

- (void)layoutSubviews{

CGSize size = [_review_content.text boundingRectWithSize:CGSizeMake(300, 1000) options: NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13.0]} context:nil].size;

_reviewLabelHeight.constant = size.height;

}

2.2

2.2.1

同样的,弄个背景View加到self.view上。添加单击手势。

2.2.2

*遇到难点:(1)在textView上加一个类似placheholder的提示语。(textfile的有这个属性,textView没有)

*解决方法:在textview上加一个Label,然后在textView的代理方法中 #pragma mark textView代理方法

- (void)textViewDidBeginEditing:(UITextView *)textView {

self.promptLabel.hidden = YES;

2.2.3

*遇到难点:(2)怎样判断textView没有输入内容已经输入的为空格。

*解决方法:

/*

//进行一个过滤,找出空格

NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];

NSString *trimedString = [self.textView.text stringByTrimmingCharactersInSet:set];

*/

if (self.textView.text.length !=0&&trimedString.length !=0) {

}

3.下载管理界面

3.1

3.1.1

*遇到难点:书名高度自适应,cell高度自适应

*解决方法:参考2.1.2

3.1.2

实现侧滑删除:

/**
 *  1.开启允许编辑
 *  2.提交编辑
 *  3.把英文转换成中文
 */
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
    return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        DownBookInfoEntity *listModel = self.downloadArrM[indexPath.row];
        [DAO_DownBook deleteBookInfoWithBookID:(NSString *)listModel.ID];
        NSString *bookUrl = [NSString stringWithFormat:@"%@%@",Host1,listModel.file];
        NSString *path = [MANAGER_FILE.CSDownloadPath stringByAppendingPathComponent:[NSString stringWithFormat:@"file/%@", [bookUrl lastPathComponent]]];
        /*从数据库删除*/
        [MANAGER_FILE deleteFolderPath:path];
        [self.downloadrrM removeObjectAtIndex:indexPath.row];
        //数组是[indexPath]的数组
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }
}
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return @"删除";
}

4.电子书阅读

用我的方法,就不用管电子书的宽高,它会自适应。

其实电视书是把一个UIScrollView加到控制器上,然后把pdfView加到UIScrollView上。

/*获取pdf文件*/
pdf = CGPDFDocumentCreateWithURL((CFURLRef)url);
/*获取文件总页数*/
pageCount = (int)CGPDFDocumentGetNumberOfPages(pdf);
-(void)drawInContext:(CGContextRef)context atPageNo:(int)page_no{
    CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
    CGContextFillRect(context,self.bounds);
    CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    if (self.pageNO == 0) {
        self.pageNO = 1;
    }
    CGPDFPageRef page = CGPDFDocumentGetPage(self.pdfDocument, self.pageNO);
    CGContextSaveGState(context);
    CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, self.bounds, 0, true);
    CGContextConcatCTM(context, pdfTransform);
    CGContextDrawPDFPage(context, page);
    CGContextRestoreGState(context);

}

四.其它总结

1.文件下载

ASIHttpRequest很好用的网络请求第三方。可以get,post请求,支持断点下载。

/**
 *  下载文件
 *  @param urlStr 文件路径
 *  @param block  回调
 */
- (void)downloadFile:(NSString *)urlStr withType:(int)type finishCallbackBlock:(void (^)(BOOL result))block {
-
    ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:urlStr]];

    NSString *filename = [urlStr lastPathComponent];
//下载后存储文件名
    NSString *savePath = [MANAGER_FILE.CSDownloadPath stringByAppendingPathComponent:[NSString stringWithFormat:@"file/%@", filename]];
    NSString *tempPath = [MANAGER_FILE.CSDownloadPath stringByAppendingPathComponent:[NSString stringWithFormat:@"temp/%@", filename]];

    [request setDownloadDestinationPath:savePath];
    [request setTemporaryFileDownloadPath:tempPath];
    [request setShouldContinueWhenAppEntersBackground:YES];
    [request setDownloadProgressDelegate:self];
    [MANAGER_SHOW showProgressWithInfo:@"下载中..."];
    [request setCompletionBlock:^{
        [MANAGER_SHOW setProgress:1.0];
        if ([MANAGER_FILE fileExists:savePath]) {
            block(YES);
        }else {
            block(NO);
        }
    }];
    [request setFailedBlock:^{
        [MANAGER_SHOW setProgress:1.0];
        block(NO);
    }];
    [request startAsynchronous];
}

2.get请求

/*
typedef void (^GetBackBlock)(id obj);
typedef void (^GetFailBlock)(NSError *error);
*/
- (void)doGetJson:(NSString *)urlstr withCompletionBlock:(GetBackBlock)completionBlock withFailBlock:(GetFailBlock)failBlock {
    ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:urlstr]];
    [request startAsynchronous];
    __block ASIHTTPRequest *_request = request;
    [request setCompletionBlock:^{
        switch ([_request responseStatusCode]) {//HTTP状态码
            case 404://Not Found 无法找到指定位置的资源
            case 500://Internal Server Error 服务器遇到了意料不到的情况
                failBlock([_request error]);
                break;
            case 200://OK 一切正常
                completionBlock([_request responseData]);
                [MANAGER_SHOW dismiss];
                break;
            default:
                failBlock([_request error]);
                break;
        }
    }];
    [request setFailedBlock:^{
        failBlock([_request error]);
        [MANAGER_SHOW dismiss];
    }]
}

3.post传输

- (void)doPostJson:(PostModel *)model withSuccessBlock:(GetBackBlock)successBlock withFailBlock:(GetFailBlock)failBlock {
    ASIFormDataRequest *request = [[ASIFormDataRequest alloc] initWithURL:[NSURL URLWithString:[model.urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];

    [request setRequestMethod:@"POST"];
    for (NSString *key in [model.params allKeys]) {
        [request setPostValue:[model.params objectForKey:key] forKey:key];
    }
    [request buildPostBody];
    [request startAsynchronous];

    __block ASIFormDataRequest *_request = request;
    [request setCompletionBlock:^{
        [MANAGER_SHOW dismiss];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            BLOCK_SUCCESS([_request responseData]);
        });
    }];
    [request setFailedBlock:^{
        [MANAGER_SHOW dismiss];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            BLOCK_FAILURE([_request error]);
        });
    }];
}
时间: 2024-10-12 02:06:41

(一)iOS开发--电子书模块的设计制作的相关文章

IOS开发环境更换后重新制作Provisioning Profile证书详解

新换了台Macbook,又折腾了一遍Provisioning Profile证书,苹果的证书繁锁复杂,每次制作都相当麻烦,而且Provisioning Profile证书是与设备绑定的,所以更换开发环境后需要重新制作. Provisioning Profile证书这个东西是很有苹果特色的一个东西,一般称之为PP证书,该证书将AppID.开发者证书和设备绑定到一起. 删除原有Provisioning Profile: 如果原有Provisioning Profile证书在其他设备还有用,可忽略此步

IOS开发之自动布局框架设计(二)

[上集剧情概要:上集我们主要剖析了原生的NSLayoutConstraint实现自动布局的方式,我们知道是通过constraintWithItem这个初始化的方法来配备所需要的7个参数,然后通过addConstraint方法将布局添加进去,并且定义了 NSLayoutAttribute,NSLayoutRelation这些枚举] 如果我们自己设计一款布局框架可以怎么设计呢? 1.封装原有的NSLayoutConstraint类,可以将代码的实现更加简洁化.例如:Masonry,SDAutoLay

IOS开发之代理的设计小技巧

1.关于代理对象的设计小技巧 在设计一个类,需要通过代理和协议来从外部获取需要的动态的数据.那么在这里设计使用代理会有两种方法. <第一种方法> 也是比较常见的: 在你设计的类中,声明一个代理属性 然后外部使用的时候 最后根据那个<...Protocol>协议,去遵循这个协议并实现协议的方法. <第二种方法>在创建这个你要设计的类对象的构造方法中添加一个代理对象的参数,目的就是按照需要,你如果要创建这个对象,你必须添加代理对象. 这样外部在创建这个对象的时候,使用这个方

iOS开发笔记--静态库的制作与使用

一.iOS项目中库的使用 1.开源库 * 公开源代码,能看到具体实现 *比如SDWebImage.AFNetworking 2.闭源库 * 不公开源代码,是经过编译后的二进制文件,看不到具体实现 * 主要分为:静态库.动态库(注意自己制作的动态库不能上传到appStore) 二.本文首先讲的的是静态库的制作以及使用 1.新建静态库项目 新建静态库项目选择cocoa Touch Static Library 然后编写核心代码 2.分别在真机和模拟器下编译生成对应环境的静态库 (注意真机文件夹下得静

[转] iOS开发之使用lipo命令制作模拟器与真机通用静态库

转自 http://blog.csdn.net/jinglijun/article/details/8276089 通常在项目中使用静态库的时候都会有两个版本,一个用于模拟器,一个用于真机,因为Mac和iPhone的CPU不同,才造成了这种情况. 为了模拟器与真机之间切换调试的方便,制作通用版本非常有必要. 现在有两个版本的静态库libSQLite_i386.a(模拟器)与libSQLite_arm.a(真机). 1.打开终端,进入到这两个文件所在的目录: 2.执行:lipo -create l

【iOS开发-62】自定义cell制作团购页面、顶部图片轮播、底部模拟加载更多功能,核心是练习代理模式

(1)效果 (2)案例源代码免费下载 团购页面+iOS源代码+头部广告轮播+底部加载更多 (3)补充 在源代码中,有一处瑕疵:就是因为是单线程,所以在上下拖动页面的时候,上面的图片轮播会停止.所以我们需要兼顾,解决方案,把定时器加到当前的runLoop中. 即在WPTgHeaderView.m的playOn方法中添加一行代码: -(void)playOn{ timer=[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector

IOS开发之自动布局框架设计(三)

[上集剧情概要:上集我们主要试着用连式结构写了一个简单地布局的设计的demo,首先通过block方式实现链式调用,然后封装添加布局的约束到block里面,实现了上下左右的简单布局] 好吧,各位观众,接下来抛砖引玉,逐渐去添加一些布局功能的时候到了..... 首先,我们考虑一个问题,因为上集我们主要是默认相对视图为superview,而且都是用默认偏移量constant,并没有倍数关系,那么我们如何加入toItem和multiplier这两个参数呢??? 用什么方式展示给用户更为好的呢??? 思考

ios开发-电话本的设计与实现

#import <UIKit/UIKit.h> #import "SubViewController.h" @interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,SubViewControllerDelegate> @end #import "SubViewController.h" @interface SubViewCo

IOS开发之微博的设计与实现

// // main.m // Microblog // #import <Foundation/Foundation.h> #import "Person.h" #import "BlogMaster.h" #import "Microblog.h" int main(int argc, const char * argv[]) { Person * person = [[Person alloc]init]; [person sh