Code Monkey home page Code Monkey logo

lazyscrollview's Introduction

##LazyScrollView简介

LazyScrollView 继承自ScrollView,目标是解决异构(与TableView的同构对比)滚动视图的复用回收问题。它可以支持跨View层的复用,用易用方式来生成一个高性能的滚动视图。此方案最先在天猫iOS客户端的首页落地。

----苹果核 - iOS 高性能异构滚动视图构建方案 —— LazyScrollView

这篇文章中,博主详细介绍了LazyScrollView的使用和实现方案,但是并没有给出具体DEMO,这里只是站在巨人的肩膀上,给一个DEMO,同时也希望可以抛砖引玉。

##LazyScrollView使用 暂时的实现比较简陋,目前只有一个id<LazyScrollViewDataSource> dataSource;,需要实现下面三个接口:

@protocol LazyScrollViewDataSource <NSObject>
@required
// ScrollView一共展示多少个item
- (NSUInteger)numberOfItemInScrollView:(LazyScrollView *)scrollView;
// 要求根据index直接返回RectModel
- (LSVRectModel *)scrollView:(LazyScrollView *)scrollView rectModelAtIndex:(NSUInteger)index;
// 返回下标所对应的view
- (UIView *)scrollView:(LazyScrollView *)scrollView itemByLsvId:(NSString *)lsvId;
@end

其中LSVRectModel就是原文中的TMMuiRectModel

@interface LSVRectModel : NSObject
// 转换后的绝对值rect
@property (nonatomic, assign) CGRect absRect;
// 业务下标
@property (nonatomic, copy) NSString *lsvId;
+ (instancetype)modelWithRect:(CGRect)rect lsvId:(NSString *)lsvId;
@end

三个接口都很简单,和UITableView很类似,如果有不清楚,可以在底部查看DEMO或者原文。

另外,LazyScrollView提供了三个接口,也都是仿照UITableView来的,所以整个LazyScrollView的使用应该是很容易上手的:

- (void)reloadData;
- (UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier;
- (void)registerClass:(Class)viewClass forViewReuseIdentifier:(NSString *)identifier;

##LazyScrollView实现 最主要的思路就是复用,所以有两个View池:

@property (nonatomic, strong) NSMutableDictionary<NSString *, NSMutableSet *> *reuseViews;
@property (nonatomic, strong) NSMutableSet<__kindof UIView *> *visibleViews;

由于每个View可能对应不同的identifier,所以reuseViews是一个NSMutableDictionary。 当一个View滑出可见区域之后,会将它先从visibleViews中移除,然后添加到reuseViews中,并从LazyScrollViewremove,即调用removeFromSuperview。这个地方在原文中作者的表述可能让大家误会了。

LazyScrollView中有一个Dictionary,key是reuseIdentifier,Value是对应reuseIdentifier被回收的View,当LazyScrollView得知这个View不该再出现了,会把View放在这里,并且把这个View hidden掉。

这里作者用的是hidden掉,但是我们知道,hidden只是控制显隐,View本身还是在那里,也无法去复用。

而当一个View滑到可见区域内时,需要先从reuseViews中复用,如果reuseViews没有,则重新创建一个。相关实现请看- (UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier;

最后一个问题就是如何判断一个View是在可见区域内的。这里原文中说的很清晰,还有图片配合。建议大家还是移步原文。这里我简单说一下,找到顶边大于contentOffset.y - BUFFER_HEIGHT,底边小于contentOffset.y+CGRectGetHeight(self.bounds) + BUFFER_HEIGHT,然后两个集合取交集就是需要显示的View集合了。 当然,这里有一些处理算法:

  • 顶边 做升序处理得到一个集合,对 底边 降序处理得到一个集合。
  • 采用二分法查找合适的位置,然后再对上一步得到的集合取子集即可。

好了,说了这么多,先放出DEMO地址吧,希望大家可以帮助完善,也希望可以给个Star。https://github.com/HistoryZhang/LazyScrollView

原文地址:苹果核 - iOS 高性能异构滚动视图构建方案 —— LazyScrollView(里面还有很多干货)。

最后说一下目前写的几个问题,希望大家可以一起来优化:

  • 没有处理View点击事件,即没有写delegate回调。

  • 二分法查找合适位置的时候算法待优化。

  • 从旧的visibleViews中移除被滑出的View算法待优化。

贴一段第二个问题的代码:

- (NSMutableSet *)findSetWithMinEdge:(CGFloat)minEdge {
    NSArray *ascendingEdgeArray =
    [self.allRects sortedArrayUsingComparator:^NSComparisonResult(LSVRectModel *obj1, LSVRectModel *obj2) {
        return CGRectGetMinY(obj1.absRect) > CGRectGetMinY(obj2.absRect) ? NSOrderedDescending : NSOrderedAscending;
    }];
    
    // TOOD: 此处待优化
    // 二分法
    NSInteger minIndex = 0;
    NSInteger maxIndex = ascendingEdgeArray.count - 1;
    NSInteger midIndex = (minIndex + maxIndex) / 2;
    LSVRectModel *model = ascendingEdgeArray[midIndex];
    while (minIndex < maxIndex - 1) {
        if (CGRectGetMinY(model.absRect) > minEdge) {
            maxIndex = midIndex;
        }
        else {
            minIndex = midIndex;
        }
        midIndex = (minIndex + maxIndex) / 2;
        model = ascendingEdgeArray[midIndex];
    }
    midIndex = MAX(midIndex - 1, 0);
    NSArray *array = [ascendingEdgeArray subarrayWithRange:NSMakeRange(midIndex, ascendingEdgeArray.count - midIndex)];
    return [NSMutableSet setWithArray:array];
}

再贴一段第三个问题的代码:

    NSMutableArray *newVisibleViews = [self visiableViewModels].mutableCopy;
    NSMutableArray *newVisibleLsvIds = [newVisibleViews valueForKey:@"lsvId"];
    NSMutableArray *removeViews = [NSMutableArray array];
    for (UIView *view in self.visibleViews) {
        if (![newVisibleLsvIds containsObject:view.lsvId]) {
            [removeViews addObject:view];
        }
    }
    for (UIView *view in removeViews) {
        [self.visibleViews removeObject:view];
        [self enqueueReusableView:view];
        [view removeFromSuperview];
    }

##项目引用 已经支持cocoapods,在Podfile中添加 pod 'LazyScrollView'然后pod update即可。

##更新记录

  • 2016.12.27 新增delegate

    新增了@protocol LazyScrollViewDelegate <NSObject, UIScrollViewDelegate>。其中有一个接口:

     @optional
     - (void)scrollView:(LazyScrollView *)scrollView didClickItemAtLsvId:(NSString *)lsvId;
    

    由于lsvIdScrollView中是唯一了,这里就没有使用index了。

  • 2016.12.04 实现基本功能

lazyscrollview's People

Contributors

kelvinqq 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

Watchers

 avatar  avatar  avatar

lazyscrollview's Issues

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.