美文网首页iOS开发SwiftSwiftSwift开发
4.IOS(swift)-scrollView(tableVie

4.IOS(swift)-scrollView(tableVie

作者: 俊瑶先森 | 来源:发表于2015-05-27 21:36 被阅读1585次

    Table View 中图片加载逻辑的优化

    虽然这种优化方式在现在的机能和网络环境下可能看似不那么必要,但在我最初看到这个方法是的 09 年(印象中是 Tweetie 作者在 08 年写的 Blog,可能有误),遥想 iPhone 3G/3GS 的机能,这个方法为多图的 table view 的性能带来很大的提升,也成了我的秘密武器。而现在,在移动网络环境下,你依然值得这么做来为用户节省流量。

    先说一下原文的思路:

    1. 当用户手动 drag table view 的时候,会加载 cell 中的图片;
    2. 在用户快速滑动的减速过程中,不加载过程中 cell 中的图片(但文字信息还是会被加载,只是减少减速过程中的网络开销和图片加载的开销);
    3. 在减速结束后,加载所有可见 cell 的图片(如果需要的话);
    问题 1:

    前面提到,刚开始拖动的时候,dragging 为true,decelerating为false;decelerate过程中,dragging和decelerating都为true;decelerate 未结束时开始下一次拖动,dragging和decelerating依然都为true。所以无法简单通过table view的dragging和decelerating判断是在用户拖动还是减速过程。

    解决这个问题很简单,添加一个变量如userDragging,在 willBeginDragging中设为true,didEndDragging中设为false。那么tableView: cellForRowAtIndexPath: 方法中,是否load 图片的逻辑就是:

    if (!self.userDragging && tableView.decelerating) {
         cell.pictureView.image = nil;
         println("拖动中和减速中,不显示图片")
    } else {
         // code for loading image from network or disk
         println("拖动和减速结束,显示图片")
    }
    
    
    问题 2:

    这么做的话,decelerate结束后,屏幕上的 cell 都是不带图片的,解决这个问题也不难,你需要一个形如loadImageForVisibleCells的方法,加载可见cell的图片:

    func loadImageForVisibleCells(){
            var cells:NSArray = self.tableView.visibleCells()
            for cell in cells {
                var indexPath:NSIndexPath = self.tableView.indexPathForCell(cell as! UITableViewCell)!
                self.setupCell(cell as! TableViewCell, widthIndexPath: indexPath)
            }
    }
    
    
    问题 3:

    这个问题可能不容易被发现,在减速过程中如果用户开始新的拖动,当前屏幕的cell并不会被加载(前文提到的调用顺序问题导致),而且问题 1 的方案并不能解决问题 3,因为这些 cell 已经在屏上,不会再次经过 cellForRowAtIndexPath 方法。虽然不容易发现,但解决很简单,只需要在 scrollViewWillBeginDragging: 方法里也调用一次 loadImageForVisibleCells 即可。

    再优化

    上述方法在那个年代的确提升了table view的performance,但是你会发现在减速过程最后最慢的那零点几秒时间,其实还是会让人等得有些心急,尤其如果你的 App 只有图片没有文字。在 iOS 5 引入了 scrollViewWillEndDragging: withVelocity: targetContentOffset: 方法后,配合 SDWebImage,我尝试再优化了一下这个方法以提升用户体验:

    1. 如果内存中有图片的缓存,减速过程中也会加载该图片
    2. 如果图片属于 targetContentOffset 能看到的 cell,正常加载,这样一来,快速滚动的最后一屏出来的的过程中,用户就能看到目标区域的图片逐渐加载
    3. 你可以尝试用类似 fade in 或者 flip 的效果缓解生硬的突然出现(尤其是像本例这样只有图片的 App)

    核心代码:

    
    func scrollViewWillBeginDragging(scrollView: UIScrollView) {
            self.userDragging = true
            self.targetRect = nil;
            self.loadImageForVisibleCells()
    }
    
    func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
            
            var targetRect:CGRect = CGRectMake(targetContentOffset.memory.x, targetContentOffset.memory.y, scrollView.frame.size.width, scrollView.frame.size.height)
             self.targetRect = NSValue(CGRect: targetRect)
    }
    
    func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
            println("结束减速")
            self.targetRect = nil;
            self.loadImageForVisibleCells()
    }
    
    

    是否需要加载图片的逻辑:

    var shouldLoadImage:Bool = true
    //判断是否重叠
    if(self.targetRect != nil  && CGRectIntersectsRect(self.targetRect!.CGRectValue(), cellFrame)){
     //判断是否有缓存,加载缓存
       var manager:SDWebImageManager=SDWebImageManager.sharedManager()
       var cache:SDImageCache = manager.imageCache
       var key:String = manager.cacheKeyForURL(targetURL)
         if((cache.imageFromMemoryCacheForKey(key)) != nil){
                                shouldLoadImage = false
          }
    }               
    //如果没有缓存,缓存图片
    if(shouldLoadImage){
    }
    

    更值得高兴的是,通过判断是否 nil,targetRect 同时起到了原来 userDragging 的作用。

    Paste_Image.png

    相关文章

      网友评论

      • Will卓然:麻烦问题一下,func loadImageForVisibleCells() 这个函数在哪里调用呢?

      本文标题:4.IOS(swift)-scrollView(tableVie

      本文链接:https://www.haomeiwen.com/subject/vpmrqttx.html