• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

LazyScrollView: iOS 高性能异构滚动视图构建方案 —— LazyScrollView ...

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

LazyScrollView

开源软件地址:

https://gitee.com/KelvinZhang/LazyScrollView

开源软件介绍:

##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 实现基本功能


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Budejie: 百思不得姐 ios 基本功能实现。发布时间:2022-03-24
下一篇:
UScaleView: 自定义刻度值控件发布时间:2022-03-24
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap