前言:
有一段时间没写博客了, "持之以恒"徽章都暗了, 实在不该。 前一段确实比較忙, ...小小地给自己的懒找个借口吧。
大二即将结束, 学习iOS也有一段时间了。今天抽点时间, 开源一个前几天刚上传的App里面的一个功能, RT, 美女图片採集器。 ? 美女.. 相信没有人不喜欢吧, 基于此, 这个小Demo应运而生。
注:?
本文正在參加博客大赛。 假设认为对你有所帮助, 还望帮忙投下票。 多谢。
?
投票链接:?http://vote.blog.csdn.net/Article/Details?articleid=37825177 (投票button在最下方)
效果演示:
看到这里, 假设还有兴趣学习的话, 能够先到我的git中下载源代码, 然后配合着源代码看我以下的解析。相信, 会让你有所收获的。
git下载链接:?BeautyPickDemo.git
涉及内容:
- 百度图片API的使用
- JSON格式数据解析
- 图片异步下载 + 离线缓存
- 图片基本操作(缩放, 删除, 加入, 保存到本地)
- 下拉刷新, 上提载入
- 幻灯片放映
- 自己定义后台显示图片
源代码解析:
一。百度图片API的使用
首先, 我们知道百度是没有对外开放图片API的, 可是我们能够通过谷歌浏览器来捕捉到訪问过程中它调用的API。有兴趣的, 能够了解下谷歌浏览器Network选项的使用, 也能够參考下这篇文章:?百度图片api
这里, 我们主要介绍怎样使用就可以。
1.百度图片通用API:
http://image.baidu.com/i?
tn=resultjsonavstar&ie=utf-8&word=刘德华&pn=0&rn=60
说明:
返回格式为json
word为查询的内容
pn为第几页
rn为一页返回的图片数量
用法:大家在浏览器地址栏输入上述地址,回车就可以看到返回的图片地址
2.百度图片分类API (我们使用的就是这个)
http://image.baidu.com/channel/listjson?pn=0&rn=30&tag1=美女&tag2=所有&ie=utf8
http://image.baidu.com/channel/listjson?
pn=0&rn=30&tag1=美女&tag2=所有&ftags=校花&ie=utf8
至于其它的, 按照这种方法都能获取到. 就不反复说明了。
至于怎样调用API, 涉及到网络编程。
开源的ASI类库做的比較好(尽管挺老的一个东西了, 也有一段时间没更新了, 可是能满足我们需求)。
从源代码中, 能够找到 网络请求ASI目录。里面有须要的文件
1。导入这里的文件
2。导入必须的框架, 包含:
SystemConfiguration.framework
MobileCoreServices.framework
CFNetwork.framework
libz.dylib
3。调用API (參见 主界面-->picVC)
@property (nonatomic,strong) ASIHTTPRequest *testRequest;
NSString* urlString = [NSString stringWithFormat:@"http://image.baidu.com/channel/listjson?pn=%d&rn=10&tag1=美女&tag2=%@", nowPage, [chooseArr objectAtIndex:nowChoose]];
urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlString];
testRequest = [ASIHTTPRequest requestWithURL:url];
[testRequest setDelegate:self];
[testRequest startAsynchronous];
就可以正常调用API。
至于怎样处理返回的数据, 以下再详细讲。
二。
JSON格式数据解析
一般的数据格式有XML和JSON, 这里由于调用百度图片API返回的数据格式是JSON, 所以我们仅仅要解析JSON就可以。
调用API成功后, 它会自己主动运行这个函数
#pragma mark - 载入数据完成
- (void)requestFinished:(ASIHTTPRequest *)request
我们仅仅须要在这里解析数据, 使用数据就可以。
这种方法返回的数据是二进制格式的NSData, 我们须要手动转为UTF8编码。能够这样获取:
//当以二进制读取返回内容时用这种方法
NSData *responseData = [request responseData];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
接下去就是奇妙的时候了, 对于这种一个字符串, 假设直接打印, 你可能会看得云里雾里的, json格式而且没有又一次排列。
可是我们能够使用JsonKit来直接解析。(文件在json解析目录中)
仅仅需这样一条语句就可以:
self.testDic = [responseString objectFromJSONString];
打印解析后的数据例如以下:
至于须要哪些, 直接取就好了。比方. 我们这里须要获取到图片的标题. url, 宽度, 高度
NSMutableDictionary *nowDic = [[NSMutableDictionary alloc]init];
[nowDic setObject:[[array objectAtIndex:i]objectForKey:@"image_url"] forKey:@"image_url"];
[nowDic setObject:[[array objectAtIndex:i]objectForKey:@"image_width"] forKey:@"image_width"];
[nowDic setObject:[[array objectAtIndex:i]objectForKey:@"image_height"] forKey:@"image_height"];
[nowDic setObject:[[array objectAtIndex:i]objectForKey:@"desc"] forKey:@"desc"];
[picArray addObject:nowDic];
三。图片异步下载+离线缓存
这里提一下SDWebImage, 我们将会使用它来实现。
详细使用參见:SDWebImage 笔记
在解析完json数据后, 我们会获取到图片相应的url。
我们能够通过訪问url获取图片。?
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
这是SDWebImage给我们提供的一个函数. 通过调用它, 我们能够实现异步下载和离线缓存。
用法:
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(SPACE / 2 , SPACE / 2 , width, height)];
NSURL *url = [NSURL URLWithString:imageInfo.thumbURL];
[imageView setImageWithURL:url placeholderImage:nil];
imageView.backgroundColor = [UIColor palePurpleColor];
[self addSubview:imageView];
异步下载,离线缓存效果:(离线缓存能够到应用沙盒中查看)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGl0d2h5bHo=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" />
四。
图片基本操作(缩放, 删除, 加入, 保存到本地)
这里涉及的主要是一些常规操作, 包含缩放, 删除, 加入, 保存到本地等。
至于删除, 通常是长按删除, 仅仅要在图片上加上长按手势响应就可以。然后弹出一个对话框, 提示用户是否删除。确定删除后, 从沙盒中清除缓存就可以。
加入手势方法:
//长按
UILongPressGestureRecognizer *longRecognizer;
longRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleSingleLongFrom:)];
[self addGestureRecognizer:longRecognizer];
从视图和沙盒中删除
//从当前视图中删除
[testArr removeObject:data];
//刷新数据
__weak picVC *blockSelf = self;
[blockSelf.waterView refreshView:testArr];
[blockSelf.waterView.infiniteScrollingView stopAnimating];
//从沙盒中删除
//打开沙盒
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString * namePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"savedPicInfo_%d.plist",nowChoose]];
NSMutableArray *picArray = [[NSMutableArray alloc] initWithContentsOfFile:namePath];
for (int i=0; i<[picArray count]; i++)
{
if ([[[picArray objectAtIndex:i]objectForKey:@"image_url"] isEqualToString:data.thumbURL])
{
[picArray removeObjectAtIndex:i];
break;
}
}
[picArray writeToFile:namePath atomically:YES];
至于缩放, 首先要弹出一个全屏显示的视图。
像这样:
//单击, 显示大图
-(void)showImage:(ImageInfo*)data
{
NSURL *url = [NSURL URLWithString:data.thumbURL];
[clickImage setImageWithURL:url placeholderImage:nil];
TGRImageViewController *viewController = [[TGRImageViewController alloc] initWithImage:clickImage.image setImageInfo:data];
viewController.transitioningDelegate = self;
[self presentViewController:viewController animated:YES completion:nil];
}
本质就是调用presentViewController:viewController。
当然。我们能够给新视图的显示加上动画效果, 例如以下:
#pragma mark - UIViewControllerTransitioningDelegate methods
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
if ([presented isKindOfClass:TGRImageViewController.class]) {
return [[TGRImageZoomAnimationController alloc] initWithReferenceImageView:clickImage];
}
return nil;
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
if ([dismissed isKindOfClass:TGRImageViewController.class]) {
return [[TGRImageZoomAnimationController alloc] initWithReferenceImageView:clickImage];
}
return nil;
}
然后, 在新视图中, 加入点击移除, 长按弹出新操作, 双指移动缩放手势就可以。
详细实现例如以下:
#pragma mark - Private methods
- (void)longPress:(UITapGestureRecognizer *)tapGestureRecognizer
{
if(tapGestureRecognizer.state == UIGestureRecognizerStateBegan)
{
[self popupActionSheet];
}
}
- (IBAction)handleSingleTap:(UITapGestureRecognizer *)tapGestureRecognizer {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)handleDoubleTap:(UITapGestureRecognizer *)tapGestureRecognizer {
if (self.scrollView.zoomScale == self.scrollView.minimumZoomScale) {
// Zoom in
CGPoint center = [tapGestureRecognizer locationInView:self.scrollView];
CGSize size = CGSizeMake(self.scrollView.bounds.size.width / self.scrollView.maximumZoomScale,
self.scrollView.bounds.size.height / self.scrollView.maximumZoomScale);
CGRect rect = CGRectMake(center.x - (size.width / 2.0), center.y - (size.height / 2.0), size.width, size.height);
[self.scrollView zoomToRect:rect animated:YES];
}
else {
// Zoom out
[self.scrollView zoomToRect:self.scrollView.bounds animated:YES];
}
}
五。
下拉刷新, 上提载入
这个功能详细在浏览图片的时候使用。 代码在picVC中。
可是由于我之前专门写过一篇这种博客。 就不再反复了。
详细能够看这里:?iOS开发-ios7下拉刷新,上提载入高速集成
六。幻灯片放映
顾名思义, 就是能够自己主动播放收藏过的美女图片.. ?
这里的原理是利用UIView的动画, 不断切换显示图片和显示效果。
切换效果例如以下:
_transitionOptions= @[[NSNumber numberWithInteger:UIViewAnimationOptionTransitionFlipFromLeft],
[NSNumber numberWithInteger:UIViewAnimationOptionTransitionFlipFromRight],
[NSNumber numberWithInteger:UIViewAnimationOptionTransitionCurlUp],
[NSNumber numberWithInteger:UIViewAnimationOptionTransitionCurlDown],
[NSNumber numberWithInteger:UIViewAnimationOptionTransitionCrossDissolve],
[NSNumber numberWithInteger:UIViewAnimationOptionTransitionFlipFromTop],
[NSNumber numberWithInteger:UIViewAnimationCurveEaseIn],
[NSNumber numberWithInteger:UIViewAnimationCurveEaseOut],
[NSNumber numberWithInteger:UIViewAnimationCurveLinear],
[NSNumber numberWithInteger:UIViewAnimationOptionAllowAnimatedContent],
[NSNumber numberWithInteger:UIViewAnimationOptionOverrideInheritedCurve],
[NSNumber numberWithInteger:UIViewAnimationOptionTransitionFlipFromTop],
[NSNumber numberWithInteger:UIViewAnimationOptionTransitionFlipFromBottom]];
然后切换图片的时候, 实现例如以下代码就可以。
?(详细參见PhotoStackView)
-(void)reloadData {
if (!self.dataSource) {
//exit if data source has not been set up yet
self.photoViews = nil;
return;
}
NSInteger numberOfPhotos = [self.dataSource numberOfPhotosInPhotoStackView:self];
NSInteger topPhotoIndex = [self indexOfTopPhoto]; // Keeping track of current photo‘s top index so that it remains on top if new photos are added
if(numberOfPhotos > 0) {
NSMutableArray *photoViewsMutable = [[NSMutableArray alloc] initWithCapacity:numberOfPhotos];
UIImage *borderImage = [self.borderImage resizableImageWithCapInsets:UIEdgeInsetsMake(self.borderWidth, self.borderWidth, self.borderWidth, self.borderWidth)];
for (NSUInteger index = 0; index < numberOfPhotos; index++) {
UIImage *image = [self.dataSource photoStackView:self photoForIndex:index];
CGSize imageSize = image.size;
if([self.dataSource respondsToSelector:@selector(photoStackView:photoSizeForIndex:)]){
imageSize = [self.dataSource photoStackView:self photoSizeForIndex:index];
}
UIImageView *photoImageView = [[UIImageView alloc] initWithFrame:(CGRect){CGPointZero, imageSize}];
photoImageView.image = image;
UIView *view = [[UIView alloc] initWithFrame:photoImageView.frame];
view.layer.rasterizationScale = [[UIScreen mainScreen] scale];
view.layer.shouldRasterize = YES; // rasterize the view for faster drawing and smooth edges
if (self.showBorder) {
// Add the background image
if (borderImage) {
// If there is a border image, we need to add a background image view, and add some padding around the photo for the border
CGRect photoFrame = photoImageView.frame;
photoFrame.origin = CGPointMake(self.borderWidth, self.borderWidth);
photoImageView.frame = photoFrame;
view.frame = CGRectMake(0, 0, photoImageView.frame.size.width+(self.borderWidth*2), photoImageView.frame.size.height+(self.borderWidth*2));
UIImageView *backgroundImageView = [[UIImageView alloc] initWithFrame:view.frame];
backgroundImageView.image = borderImage;
[view addSubview:backgroundImageView];
} else {
// if there is no boarder image draw one with the CALayer
view.layer.borderWidth = self.borderWidth;
view.layer.borderColor = [[UIColor whiteColor] CGColor];
view.layer.shadowOffset = CGSizeMake(0, 0);
view.layer.shadowOpacity = 0.5;
}
}
[view addSubview:photoImageView];
view.tag = index;
view.center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
[photoViewsMutable addObject:view];
}
// Photo views are added to subview in the photoView setter
self.photoViews = photoViewsMutable; photoViewsMutable = nil;
[self goToPhotoAtIndex:topPhotoIndex];
}
}
七。自己定义后台显示图片
这个功能就是演示效果里面, 当应用切换到后台后, 我们双击home键后显示后台程序时候, 该应用的显示效果。
比方.. ?有时候我们浏览的图片尺度比較大.. 然后切到后台的时候, 就希望把它隐藏起来.. ?
这就涉及到了Background Fetch的应用。
之前也写过一篇博客专门介绍。 这里就不反复了。
详细參见:?iOS开发-自己定义后台显示图片(iOS7-Background Fetch的应用)
好了。 到这里最终是介绍的几乎相同了。
当然。 我这里的解析都比較概括, 列举的都是几个关键代码段。
更加详细的还是须要自己去看代码。 凝视也写了, 预计没什么问题。 假设有问题, 欢迎联系我。
一口气写了3个小时的博客... ?累的够呛的。也希望, 能对你有所帮助。
本文正在參加博客大赛。
假设认为对你有所帮助, 还望帮忙投下票。
多谢。?
投票链接:?http://vote.blog.csdn.net/Article/Details?
articleid=37825177 (投票button在最下方)
学习的路上, 与君共勉。