Giter VIP home page Giter VIP logo

lbphotobrowser's Introduction

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

effect_hn.gif

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

lbphotobrowser's People

Contributors

tianliangyihou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lbphotobrowser's Issues

图片容器放在新创建的window上就完美了

如果图片容器放在新创建的window上,就不需要处理statusbar的隐藏,直接可以设置window的设置隐藏statusBar,手势返回的体验就perfect了,楼主的写法还是很好的,collectionView写的我都觉得厉害,这样可以处理大量图片都不是问题,例如聊天页面

页码指示器可以放出来吗?pageLabel

页码指示器目前改不了样式,当图片数量大于9显示pageLabel,否则显示pageControl。这个方式很奇怪,能不能,单独显示一种样式,数字或横点?把pageLabel数字的页码开放出来?

内存是不是有点问题

如果不停的点图片内存会上升,下不来,挺看好你的这个,有机会可以让我和你一起搞一下

关于设计成单利的疑问?

LBPhotoBrowserManager我看是单利的,我有点不太理解为什么设计成单利,个人感觉,对于图片的浏览,想看就点开看,看了就关闭,内存释放。单利就不会释放内存了,而您在dealloc里释放通知也没多大意义,因为根本不会执行dealloc方法的。不知道您设计成单利的初衷是?

库还是很👍的,希望我可以提几点建议

库还是很👍的,希望我可以提几点建议
1.支持横竖屏
2.支持asset图片
3.长按图片动画展示菜单
4.支持原图
5.有个loading过程
6.查看图片的时候能把状态栏隐藏,并且手势下拉图片返回的时候,上一个界面得显示状态栏
如果把这些都搞定了,那才叫做高仿微信图片浏览~~~

我遇见的崩溃问题

今天遇见到神奇的崩溃,经常排查,发现是服务器返回的图片地址有点问题,在stringurl的时候,失败掉,然后把nil值插入了数组就崩溃了。

解决办法如下:

  1. LBPhotoWebItem类的urlString属性改成copy修饰
  2. 覆写urlString的set方法,如下:
- (void)setUrlString:(NSString *)urlString
{
    NSString *url = @"";
    // 编码化url
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
    url = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
#else
    url = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
#endif
    
    _urlString = [url copy];
}

请教一个问题

如果我是用CollectionView展示多张图片,fromImageViews这个参数要传imageView的数组,我该如何传递这个参数?我想达到collectionView和点击后的图片同步滚动展示,请指教

目前发现的3个问题

1.只使用预览,不加任何长按事件,在预览的时候,长按依旧有蒙版出现。代码只使用下面这一句:

[LBPhotoBrowserManager.defaultManager showImageWithWebItems:items selectedIndex:tag fromImageViewSuperView:wcell.contentView].lowGifMemory = YES;

原因应该是,如果没有addLongPressShowTitles实现等方法,就别触发任何长按事件了。

2.同样不加任何长按事件,没有做任何回调, 预览时,状态栏没有隐藏。我感觉,默认情况下,预览应该是隐藏状态栏的,除非用户自己去实现block,自己去处理状态栏。

3.同样不加任何长按事件,没有做任何回调,当预览的图片是长度超过屏幕长度时的长方形时,下拉关闭预览失效。这个估计是你不好处理长图时滑动手势,故意这么处理的。不过我看微信很长的图片。当滑到图片顶部,继续滑动依旧能滑动关闭。

我使用时的代码方式:

    NSMutableArray *array = [NSMutableArray array];
    
    for (HWADImageModel *m in self.model.adArray) {
        LBPhotoWebItem *item = [[LBPhotoWebItem alloc] initWithURLString:m.imageURL.absoluteString frame:self.adView.frame placeholdImage:[UIImage imageNamed:@"placeholder_img"]];
        [array addObject:item];
    }
    
    [LBPhotoBrowserManager.defaultManager showImageWithWebItems:array selectedIndex:index fromImageViewSuperView:self.adView].lowGifMemory = YES;

其实我在使用的过程遇到了几个bug

1.你好,网上连续九张gif浏览时,因为内存原因,浏览过的某一张图片会被释放,整个界面变黑,
2.另外有时在dismiss图片浏览器时这行代码会有问题
self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:scalePercent / _zoomScale];
_zoomScale这个变量作为分母有时会为0
3.请教一下,支持gif,为何不考虑使用FLAnimatedImageView ,而是自己鲁?

老铁有bug啊

demo里的本地图片测试,添加2张图然后删掉第二张,就会崩溃,断点在LBPhotoBrowserView的scrollViewDidScroll里面,原因是self.models只剩一个元素,数组越界了

点击查看大图 当图片个数大于9张的时候崩溃

我的们图片最多可以达到40张,每张图片大小可以在1-2M这样的情况下你的控件必崩溃,按你说的那种方法设置了destroyImageNotNeedShow 属性根本没有用,依然崩溃,我现在都不怎么知道怎么搞了。

计算索引问题。

文件:LBPhotoBrowserShowHelper.h
static inline int lb_currentSelectImageViewIndex() {
UICollectionView *currentCollectionView = [LBPhotoBrowserManager defaultManager].currentCollectionView;
return (int)(currentCollectionView.contentOffset.x / SCREEN_WIDTH);
}

return (int)(currentCollectionView.contentOffset.x / SCREEN_WIDTH);
应该替换成
return (int)(currentCollectionView.contentOffset.x / currentCollectionView.width);

因为在创建CollectionView 时候,使用了
collectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, 20);
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH + 20, SCREEN_HEIGHT) collectionViewLayout:flowLayout];
flowLayout.minimumLineSpacing = 20;

这样根据屏幕宽度计算索引时每个元素相差20,导致计算索引位置不正确。比正常值大。
列:
iPhone 6。 屏幕宽度 375,每个相差20。 375/20 = 18.75. 在这个临界值以后索引就会出现问题。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.