tianliangyihou / LBPhotoBrowser

高仿微信和今日头条图片浏览器(LBPhotoBrowser)
MIT License
358 stars 59 forks source link

LBPhotoBrowser

一个使用简单的图片浏览器, 实现类似微信和今日头条的图片浏览效果 (如果下面的gif图加载不出来或者加载太慢,请移步简书)

简书地址:https://www.jianshu.com/p/baaab7bd47f3

新版本已经基本完成,下面的文档还没有更新,实际使用参考demo为准

概览(Overview)

LBPhotoBrowser对gif图片的加载机制:

LBPhotoBrowser对gif的播放提供了两种方式:

(1)采用系统的 + (nullableUIImage*)animatedImageWithImages:(NSArray *)images duration:(NSTimeInterval)durationNS_AVAILABLE_IOS(5_0);

(2)自定义gif的播放,具体步骤如下:

   * 获取当前手机可以利用的内存和当前展示的gif图片每帧图片加载到内存占用的大小,以取得当前内存可以加载gif的最大帧数.
     最大加载帧数 = 可利用内存 /  每帧图片的大小.

   * 使用CADisplayLink作为定时器,开始展示当前帧的图片

   * 获取当前帧的展示时间,展示完毕,切换下一帧图片.当在展示当前帧的图片的时候, 异步线程(自定义NSOperation)去取下一帧的图片,以供当前帧的图片展示
     完毕后,直接从缓存的buffer(字典)中读取.

   * 当gif图片的帧数大于当前内存适合加载的帧数的时候,buffer(字典)会不断的移除已展示过的图片,来确保加载到内存中的图片数稳定.
     如果小于可加载的最大帧数,直接全部加载到内存,节省CPU.

   * LBPhotoBrowser为了保证较低的CPU消耗,即使在图片浏览器加载多张gif的时候,也会保证同一时间内,只会对一张gif进行处理,不会同时去解压多张gif图片.

   建议使用第二种加载方式 即 lowGifMemory = YES, 通过 LBPhotoBrowserManager 的 lowGifMemory 属性控制 

   当你加载的gif图片较多,并且gif的帧数也比较多,两种方式的差别会特别明显,方式2的优点也越明显.(不要使用模拟器测试)

LBPhotoBrowser对网络图片的预加载机制:

LBPhotoBrowser 将网络图片的加载分为两种:

 (1)缩略图和大图使用同一个url 不需要提供预加载

 (2)缩略图和大图使用不同的url 提供预加载  

    * 当点击图片,通过LBPhotoBrowser展示大图的过程中,LBPhotoBrowser会自动提前加载当前图片左右两张图片,以方便用户浏览

    * 当用户在滑动图片的过程中,LBPhotoBrowser会始终保持优先加载当前展示图片和当前展示图片左右两张的图片,并且停止离当前图片较远图片的加载

    * 当用户退出LBPhotoBrowser,停止所有图片的加载

   当你使用(1)展示图片的时候,请设置`LBPhotoBrowserManager`的`needPreloading` = `NO`. 

   注:
      缩略图: 当前展示给用户的图片
        大图: 点击缩略图后,使用LBPhotoBrowser展示给用户的图片       
LBPhotoBrowser 对网络图片的预加载机制的进一步优化: 增加 destroyImageNotNeedShow 属性

问   题:
当用户在不停浏览图片的过程中,我们通过预加载机制默默的替用户加载着图片.
比如:用户浏览了20张图片(一般没这么多哈),这时候LBPhotoBrowser会将这20张图片都保存在内存中(会有一个强请引用).(没具体看过其他的图片浏览器怎么做的,不过我猜多数应该也是这样)
这样其实是有些不合理,用户可能只关心当前浏览的图片,至于之前浏览过图片的这时候不应该存在内存当中.一旦用户又要重新浏览这些图片.我们也可以通过预加载机制读取SDWebImage的缓存,这样来减少内存的消耗.

解决办法:
原有的预加载机制,只会加载当前展示的图片和当前展示图片左右两张的图片.不在当前展示范围的图片不会去加载. 已经加载过了的图片会保存在内存中.
故:将所有不在预加载的范围内的图片(已经加载过的),清除内存缓存(取消强引用).

问题: 使用destroyImageNotNeedShow 发现内存没什么变化.有点尴尬😓

原因: SDWebImage会做内存缓存,当我们不对图片强引用的时候,SDWebImage依然会图片有一个强引用. 所以图片不会销毁. 
但是SDWebImage 虽然会对图片做一个引用,但是一旦收到内存警告,SDWebImage就会清除这个引用.

解决办法:
对于展示较少张数的图片,不建议开启destroyImageNotNeedShow(默认NO)这个属性
对于展示图片的张数比较多情况(9张以上),开启destroyImageNotNeedShow = YES,进行优化

使用(Usage)

LBPhotoBrowser 支持本地图片和网络图片 以及gif的播放,下面四中效果详情可参考demo

效果1: 加载本地图片,支持相册中的gif的图片

  NSMutableArray *items = [[NSMutableArray alloc]init];
  for (UIImageView *imageView in self.imageViews) {
        LBPhotoLocalItem *item = [[LBPhotoLocalItem alloc]initWithImage:imageView.image frame:imageView.frame];
        [items addObject:item];
    }
  [[LBPhotoBrowserManager defaultManager]showImageWithWebItems:items selectedIndex:tag fromImageViewSuperView:self.view];

效果2: 加载网络图片,实现类似微信的图片浏览效果,缩略图和大图使用不同的url

 NSMutableArray *items = [[NSMutableArray alloc]init];
 for (int i = 0 ; i < cellModel.urls.count; i++) {
       LBURLModel *urlModel = cellModel.urls[i];
        UIImageView *imageView = cell.imageViews[i];
        LBPhotoWebItem *item = [[LBPhotoWebItem alloc]initWithURLString:urlModel.largeURLString frame:imageView.frame];
        item.placeholdImage = imageView.image;
        [items addObject:item];
     }
   [LBPhotoBrowserManager.defaultManager showImageWithWebItems:items selectedIndex:tag fromImageViewSuperView:cell.contentView].lowGifMemory = YES;

效果3: 加载网络图片,实现类似今日头条的图片浏览效果,缩略图和大图使用不同的url

 NSMutableArray *items = [[NSMutableArray alloc]init];
 for (int i = 0 ; i < cellModel.urls.count; i++) {
       LBURLModel *urlModel = cellModel.urls[i];
        UIImageView *imageView = cell.imageViews[i];
        LBPhotoWebItem *item = [[LBPhotoWebItem alloc]initWithURLString:urlModel.largeURLString frame:imageView.frame placeholdImage:imageView.image placeholdSize:imageView.frame.size];
         [items addObject:item];
   }
  [LBPhotoBrowserManager.defaultManager showImageWithWebItems:items selectedIndex:tag fromImageViewSuperView:cell.contentView].lowGifMemory = YES;

效果4: 加载网络图片 缩略图和大图使用同一个url

 NSMutableArray *items = [[NSMutableArray alloc]init];
 for (int i = 0 ; i < cellModel.urls.count; i++) {
        LBURLModel *urlModel = cellModel.urls[i];
        UIImageView *imageView = cell.imageViews[i];
         LBPhotoWebItem *item = [[LBPhotoWebItem alloc]initWithURLString:urlModel.largeURLString frame:imageView.frame];
         [items addObject:item];
     }
  [LBPhotoBrowserManager.defaultManager showImageWithWebItems:items selectedIndex:tag fromImageViewSuperView:cell.contentView].lowGifMemory = YES;
  [[LBPhotoBrowserManager defaultManager]addPhotoBrowserWillDismissBlock:^{
    // do something       
   }].needPreloading = NO;

提示(Tip)

关于图片展示过程中,status bar的控制
对于status bar的处理,相比之前做了较大的优化
采用创建一个新的level 高于status bar 的window 覆盖在之前的window上
效果更佳流畅和自然 (上面展示效果的gif图片 是采用了之前版本的处理方式,如果感觉不流畅,请忽略)
保存gif图片的问题
由于 SDWebImage 返回的image只是这个gif图片的第一帧

1 当lowGifMemory = NO 的情况下,可以直接过
// 默认长按控件的回调
- (instancetype)addTitleClickCallbackBlock:(void(^)(UIImage *image,NSIndexPath *indexPath,NSString *title))titleClickCallBackBlock;
add 这个block 返回的image 进行保存

2 当lowGifMemory = YES的情况下,通过下面这个block返回的data进行保存, 这个也适合方式1
 [[SDImageCache sharedImageCache] queryCacheOperationForKey:currentUrl.absoluteString done:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {

 }];
使用 LBPhotoBrowser 的时候 当你需要添功能的时候 就尝试add Block, LBPhotoBrowser可以无限add block,同一个block add多次,后添加的生效

所以你可以这样写,可以更长^_^ ,当然也可以分开写

    [[[[LBPhotoBrowserManager.defaultManager addLongPressShowTitles:@[@"保存",@"识别二维码",@"取消"]]addTitleClickCallbackBlock:^(UIImage *image, NSIndexPath *indexPath, NSString *title) {
            // do somehting
        }]addPhotoBrowserWillDismissBlock:^{
            // do somehting
        }]addPhotoBrowserDidDismissBlock:^{
            // do somehting
        }];
关于SDWebImage加载gif图片的问题(sd_setImageWithURL):
当你在真机上运行当前版本的时候,你会发现展示gif的一个问题 => 拖动pop当前界面的时候,imageView上的图片不见了

这个是SDWebImage内部的一个方法导致的.

你可以在demo的style3中(右上角有个测试按钮)中找到原因和解决办法
LBPhotoBrowser的依赖
 LBPhotoBrowser 只依赖于SDWebImage,本身实现了gif的解压和播放

相关(Relevant)

这是本人写的一个高仿今日头条的项目,目前还在完善中 部分已有的功能如下:

采用了RAC + MVVM 的方式  使用了LBPhotoBrowser

https://github.com/tianliangyihou/headlineNews

effect_hn.gif

如果您使用过程中发现什么问题,请及时issue me 或者 简书 下面给我留言 期待和您一起改进LBPhotoBrowser