美女图片采集器 (源码+解析)

前言:


有一段时间没写博客了, "持之以恒"徽章都暗了, 实在不该。 前一段确实比较忙, ...小小地给自己的懒找个借口吧。 大二即将结束, 学习iOS也有一段时间了。今天抽点时间, 开源一个前几天刚上传的App里面的一个功能, RT, 美女图片采集器。   美女.. 相信没有人不喜欢吧, 基于此, 这个小Demo应运而生。


注: 


本文正在参加博客大赛。 如果觉得对你有所帮助, 还望帮忙投下票。 多谢。 

投票链接: http://vote.blog.csdn.net/Article/Details?articleid=37825177 (投票按钮在最下方)

效果演示:




看到这里, 如果还有兴趣学习的话, 可以先到我的git中下载源码, 然后配合着源码看我下面的解析。相信, 会让你有所收获的。

git下载链接: BeautyPickDemo.git


涉及内容:


  1. 百度图片API的使用
  2. JSON格式数据解析
  3. 图片异步下载 + 离线缓存
  4. 图片基本操作(缩放, 删除, 添加, 保存到本地)
  5. 下拉刷新, 上提加载
  6. 幻灯片放映
  7. 自定义后台显示图片

源码解析:



一。百度图片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;

      
      
      
      


      
      
      
      
  1. NSString* urlString = [ NSString stringWithFormat: @"http://image.baidu.com/channel/listjson?pn=%d&rn=10&tag1=美女&tag2=%@", nowPage, [chooseArr objectAtIndex:nowChoose]];
  2. urlString = [urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
  3. NSURL *url = [ NSURL URLWithString:urlString];
  4. testRequest = [ASIHTTPRequest requestWithURL:url];
  5. [testRequest setDelegate: self];
  6. [testRequest startAsynchronous];

即可正常调用API。至于如何处理返回的数据, 下面再详细讲。

二。JSON格式数据解析

一般的数据格式有 XMLJSON, 这里因为调用百度图片API返回的数据格式是JSON, 所以我们只要解析JSON即可。
调用API成功后, 它会自动执行这个函数

      
      
      
      
  1. #pragma mark - 加载数据完毕
  2. - ( void)requestFinished:(ASIHTTPRequest *)request
我们只需要在这里解析数据, 使用数据即可。

这个方法返回的数据是二进制格式的NSData, 我们需要手动转为UTF8编码。可以这样获取:

      
      
      
      
  1. //当以二进制读取返回内容时用这个方法
  2. NSData *responseData = [request responseData];
  3. NSString *responseString = [[ NSString alloc] initWithData:responseData encoding: NSUTF8StringEncoding];

接下去就是神奇的时候了, 对于这样的一个字符串, 如果直接打印, 你可能会看得云里雾里的, json格式并且没有重新排列。
但是我们可以使用JsonKit来直接解析。(文件在json解析文件夹中)

只需这样一条语句即可:
self.testDic = [responseString objectFromJSONString];
      
      
      
      

打印解析后的数据如下:



至于需要哪些, 直接取就好了。比如. 我们这里需要获取到图片的标题. url, 宽度, 高度

      
      
      
      
  1. NSMutableDictionary *nowDic = [[ NSMutableDictionary alloc]init];
  2. [nowDic setObject:[[array objectAtIndex:i]objectForKey: @"image_url"] forKey: @"image_url"];
  3. [nowDic setObject:[[array objectAtIndex:i]objectForKey: @"image_width"] forKey: @"image_width"];
  4. [nowDic setObject:[[array objectAtIndex:i]objectForKey: @"image_height"] forKey: @"image_height"];
  5. [nowDic setObject:[[array objectAtIndex:i]objectForKey: @"desc"] forKey: @"desc"];
  6. [picArray addObject:nowDic];


三。图片异步下载+离线缓存


这里提一下SDWebImage, 我们将会使用它来实现。 具体使用参见: SDWebImage 笔记
在解析完json数据后, 我们会获取到图片对应的url。
我们可以通过访问url获取图片。 
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
      
      
      
      
这是SDWebImage给我们提供的一个函数. 通过调用它, 我们可以实现异步下载和离线缓存。

使用方法:

      
      
      
      
  1. UIImageView *imageView = [[ UIImageView alloc]initWithFrame: CGRectMake(SPACE / 2 , SPACE / 2 , width, height)];
  2. NSURL *url = [ NSURL URLWithString:imageInfo.thumbURL];
  3. [imageView setImageWithURL:url placeholderImage: nil];
  4. imageView.backgroundColor = [ UIColor palePurpleColor];
  5. [ self addSubview:imageView];


异步下载,离线缓存效果:(离线缓存可以到应用沙盒中查看)




四。图片基本操作(缩放, 删除, 添加, 保存到本地)


这里涉及的主要是一些常规操作, 包括缩放, 删除, 添加, 保存到本地等。
至于删除, 一般是长按删除, 只要在图片上加上长按手势响应即可。然后弹出一个对话框, 提示用户是否删除。确定删除后, 从沙盒中清除缓存即可。
添加手势方法:

      
      
      
      
  1. //长按
  2. UILongPressGestureRecognizer *longRecognizer;
  3. longRecognizer = [[ UILongPressGestureRecognizer alloc]initWithTarget: self action: @selector(handleSingleLongFrom:)];
  4. [ self addGestureRecognizer:longRecognizer];

从视图和沙盒中删除

      
      
      
      
  1. //从当前视图中删除
  2. [testArr removeObject:data];
  3. //刷新数据
  4. __ weak picVC *blockSelf = self;
  5. [blockSelf.waterView refreshView:testArr];
  6. [blockSelf.waterView.infiniteScrollingView stopAnimating];
  7. //从沙盒中删除
  8. //打开沙盒
  9. NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
  10. NSString *documentsDirectory = [paths objectAtIndex: 0];
  11. NSString * namePath = [documentsDirectory stringByAppendingPathComponent:[ NSString stringWithFormat: @"savedPicInfo_%d.plist",nowChoose]];
  12. NSMutableArray *picArray = [[ NSMutableArray alloc] initWithContentsOfFile:namePath];
  13. for ( int i= 0; i<[picArray count]; i++)
  14. {
  15. if ([[[picArray objectAtIndex:i]objectForKey: @"image_url"] isEqualToString:data.thumbURL])
  16. {
  17. [picArray removeObjectAtIndex:i];
  18. break;
  19. }
  20. }
  21. [picArray writeToFile:namePath atomically: YES];

至于缩放, 首先要弹出一个全屏显示的视图。
像这样:

      
      
      
      
  1. //单击, 显示大图
  2. -( void)showImage:(ImageInfo*)data
  3. {
  4. NSURL *url = [ NSURL URLWithString:data.thumbURL];
  5. [clickImage setImageWithURL:url placeholderImage: nil];
  6. TGRImageViewController *viewController = [[TGRImageViewController alloc] initWithImage:clickImage.image setImageInfo:data];
  7. viewController.transitioningDelegate = self;
  8. [ self presentViewController:viewController animated: YES completion: nil];
  9. }

本质就是调用presentViewController:viewController。
当然,我们可以给新视图的显示加上动画效果, 如下:

      
      
      
      
  1. #pragma mark - UIViewControllerTransitioningDelegate methods
  2. - ( id< UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:( UIViewController *)presented presentingController:( UIViewController *)presenting sourceController:( UIViewController *)source
  3. {
  4. if ([presented isKindOfClass:TGRImageViewController.class]) {
  5. return [[TGRImageZoomAnimationController alloc] initWithReferenceImageView:clickImage];
  6. }
  7. return nil;
  8. }
  9. - ( id< UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:( UIViewController *)dismissed {
  10. if ([dismissed isKindOfClass:TGRImageViewController.class]) {
  11. return [[TGRImageZoomAnimationController alloc] initWithReferenceImageView:clickImage];
  12. }
  13. return nil;
  14. }


然后, 在新视图中, 添加点击移除, 长按弹出新操作, 双指移动缩放手势即可。
具体实现如下:

      
      
      
      
  1. #pragma mark - Private methods
  2. - ( void)longPress:( UITapGestureRecognizer *)tapGestureRecognizer
  3. {
  4. if(tapGestureRecognizer.state == UIGestureRecognizerStateBegan)
  5. {
  6. [ self popupActionSheet];
  7. }
  8. }
  9. - ( IBAction)handleSingleTap:( UITapGestureRecognizer *)tapGestureRecognizer {
  10. [ self dismissViewControllerAnimated: YES completion: nil];
  11. }
  12. - ( IBAction)handleDoubleTap:( UITapGestureRecognizer *)tapGestureRecognizer {
  13. if ( self.scrollView.zoomScale == self.scrollView.minimumZoomScale) {
  14. // Zoom in
  15. CGPoint center = [tapGestureRecognizer locationInView: self.scrollView];
  16. CGSize size = CGSizeMake( self.scrollView.bounds.size.width / self.scrollView.maximumZoomScale,
  17. self.scrollView.bounds.size.height / self.scrollView.maximumZoomScale);
  18. CGRect rect = CGRectMake(center.x - (size.width / 2.0), center.y - (size.height / 2.0), size.width, size.height);
  19. [ self.scrollView zoomToRect:rect animated: YES];
  20. }
  21. else {
  22. // Zoom out
  23. [ self.scrollView zoomToRect: self.scrollView.bounds animated: YES];
  24. }
  25. }



五。下拉刷新, 上提加载

这个功能具体在浏览图片的时候使用。 代码在picVC中。
但是因为我之前专门写过一篇这样的博客。 就不再重复了。
详细可以看这里:  iOS开发-ios7下拉刷新,上提加载快速集成


六。幻灯片放映

顾名思义, 就是能够自动播放收藏过的美女图片..  
这里的原理是利用UIView的动画, 不断切换显示图片和显示效果。

切换效果如下:

      
      
      
      
  1. _transitionOptions= @[[ NSNumber numberWithInteger: UIViewAnimationOptionTransitionFlipFromLeft],
  2. [ NSNumber numberWithInteger: UIViewAnimationOptionTransitionFlipFromRight],
  3. [ NSNumber numberWithInteger: UIViewAnimationOptionTransitionCurlUp],
  4. [ NSNumber numberWithInteger: UIViewAnimationOptionTransitionCurlDown],
  5. [ NSNumber numberWithInteger: UIViewAnimationOptionTransitionCrossDissolve],
  6. [ NSNumber numberWithInteger: UIViewAnimationOptionTransitionFlipFromTop],
  7. [ NSNumber numberWithInteger: UIViewAnimationCurveEaseIn],
  8. [ NSNumber numberWithInteger: UIViewAnimationCurveEaseOut],
  9. [ NSNumber numberWithInteger: UIViewAnimationCurveLinear],
  10. [ NSNumber numberWithInteger: UIViewAnimationOptionAllowAnimatedContent],
  11. [ NSNumber numberWithInteger: UIViewAnimationOptionOverrideInheritedCurve],
  12. [ NSNumber numberWithInteger: UIViewAnimationOptionTransitionFlipFromTop],
  13. [ NSNumber numberWithInteger: UIViewAnimationOptionTransitionFlipFromBottom]];

然后切换图片的时候, 实现如下代码即可。  (具体参见PhotoStackView)

      
      
      
      
  1. -( void)reloadData {
  2. if (! self.dataSource) {
  3. //exit if data source has not been set up yet
  4. self.photoViews = nil;
  5. return;
  6. }
  7. NSInteger numberOfPhotos = [ self.dataSource numberOfPhotosInPhotoStackView: self];
  8. NSInteger topPhotoIndex = [ self indexOfTopPhoto]; // Keeping track of current photo's top index so that it remains on top if new photos are added
  9. if(numberOfPhotos > 0) {
  10. NSMutableArray *photoViewsMutable = [[ NSMutableArray alloc] initWithCapacity:numberOfPhotos];
  11. UIImage *borderImage = [ self.borderImage resizableImageWithCapInsets: UIEdgeInsetsMake( self.borderWidth, self.borderWidth, self.borderWidth, self.borderWidth)];
  12. for ( NSUInteger index = 0; index < numberOfPhotos; index++) {
  13. UIImage *image = [ self.dataSource photoStackView: self photoForIndex:index];
  14. CGSize imageSize = image.size;
  15. if([ self.dataSource respondsToSelector: @selector(photoStackView:photoSizeForIndex:)]){
  16. imageSize = [ self.dataSource photoStackView: self photoSizeForIndex:index];
  17. }
  18. UIImageView *photoImageView = [[ UIImageView alloc] initWithFrame:( CGRect){ CGPointZero, imageSize}];
  19. photoImageView.image = image;
  20. UIView *view = [[ UIView alloc] initWithFrame:photoImageView.frame];
  21. view.layer.rasterizationScale = [[ UIScreen mainScreen] scale];
  22. view.layer.shouldRasterize = YES; // rasterize the view for faster drawing and smooth edges
  23. if ( self.showBorder) {
  24. // Add the background image
  25. if (borderImage) {
  26. // If there is a border image, we need to add a background image view, and add some padding around the photo for the border
  27. CGRect photoFrame = photoImageView.frame;
  28. photoFrame.origin = CGPointMake( self.borderWidth, self.borderWidth);
  29. photoImageView.frame = photoFrame;
  30. view.frame = CGRectMake( 0, 0, photoImageView.frame.size.width+( self.borderWidth* 2), photoImageView.frame.size.height+( self.borderWidth* 2));
  31. UIImageView *backgroundImageView = [[ UIImageView alloc] initWithFrame:view.frame];
  32. backgroundImageView.image = borderImage;
  33. [view addSubview:backgroundImageView];
  34. } else {
  35. // if there is no boarder image draw one with the CALayer
  36. view.layer.borderWidth = self.borderWidth;
  37. view.layer.borderColor = [[ UIColor whiteColor] CGColor];
  38. view.layer.shadowOffset = CGSizeMake( 0, 0);
  39. view.layer.shadowOpacity = 0.5;
  40. }
  41. }
  42. [view addSubview:photoImageView];
  43. view.tag = index;
  44. view.center = CGPointMake( CGRectGetMidX( self.bounds), CGRectGetMidY( self.bounds));
  45. [photoViewsMutable addObject:view];
  46. }
  47. // Photo views are added to subview in the photoView setter
  48. self.photoViews = photoViewsMutable; photoViewsMutable = nil;
  49. [ self goToPhotoAtIndex:topPhotoIndex];
  50. }
  51. }



七。自定义后台显示图片

这个功能就是演示效果里面, 当应用切换到后台后, 我们双击home键后显示后台程序时候, 该应用的显示效果。
比如..  有时候我们浏览的图片尺度比较大.. 然后切到后台的时候, 就希望把它隐藏起来..  

这就涉及到了Background Fetch的应用。
之前也写过一篇博客专门介绍。 这里就不重复了。
具体参见:  iOS开发-自定义后台显示图片(iOS7-Background Fetch的应用)




好了。 到这里终于是介绍的差不多了。
当然。 我这里的解析都比较概括, 列举的都是几个关键代码段。
更加详细的还是需要自己去看代码。 注释也写了, 估计没什么问题。 如果有问题, 欢迎联系我。

一口气写了3个小时的博客...  累的够呛的。也希望, 能对你有所帮助。

本文正在参加博客大赛。 如果觉得对你有所帮助, 还望帮忙投下票。 多谢。 

投票链接: http://vote.blog.csdn.net/Article/Details?articleid=37825177 (投票按钮在最下方)



学习的路上, 与君共勉。

        
原创文章 268获赞 379访问量 237万+

你可能感兴趣的:(转载)