动态加载滑动列表实现

本文介绍了一种动态加载滑动列表的策略,通过仅加载可见及预加载部分的UI节点来节省内存。在直播平台场景中,针对500个直播间图片的管理,采取了滚动时删除多余节点的方法,保持列表节点数恒定。同时,针对滑动过快导致的加载延迟,使用加载动画过渡。此外,优化了直播列表数据的获取,仅在切换标签时请求,并在客户端缓存90秒,减少不必要的刷新。未来计划进一步优化,按需从服务端获取数据。
摘要由CSDN通过智能技术生成

动态加载滑动列表

        采用了类似分片加载的策略,仅加载出当前可以看到的图片以及一定的预加载部分,随着滑动逐渐的加载出下边的内容,但大量的UI节点会造成内存的紧张,直播平台500个直播间的图片量不能导入所有贴图,大量的贴图残留在内存中会造成不必要的问题, 因此加载策略为仅显示当前看到的ITEM以及上下的预加载部分, 向上滑动删除下边多余的UI节点, 向下滑动删除上边多余的UI节点, 总之维持列表中的节点数为常量。

  略图

        如图所示是以上滑动过快的情况下显示的加载动画, 由于UI节点是异步动态加载的, 因此存在滑动过快造成加载不及时的情况,游戏中采用加载动画进行过度。此外由于直播列表数信息量较大, 因此在从服务端拉取直播列表信息上做了些优化, 仅在点击对应直播列表的标签页时从服务端进行数据请求, 数据回来后进行列表的显示,回来之前会有加载动画的显示,并且数据会在客户端进行90秒的缓存, 避免直播列表数据不必要的刷新造成的流量浪费。后期会进一步的优化,只从服务端返回显示需要的那一部分直播列表的信息, 在向下滑动时逐步加载出所有直播列表信息。

 

以下为代码实现样例


class ScrollViewAdapter(object):
    """
        自定义的滑动列表控件, 实现分片加载, 需要找UI制作列表节点两个Layout为父子关系,
        父Layout勾选剪裁, 子Layout与父Layout大小相同左上角为锚点, 都勾选交互。Item 锚点在中心
        加载采用定时加载的策略, 每隔一定时间加载一个Item, 滑动到没有加载完成的行, 
        就显示加载中的图标, 直到加载完预加载的内容。
    """

    # 列表的状态
    STOP = 0
    DRAG_MOVE = 1
    INERTIA_MOVE = 2
    BOUND_MOVE = 3

    ##########################################################################
    # 自定义滑动列表的初始化
    ##########################################################################

    def __init__(self, scroll_view, item_node, row_count, item_data_list, create_item_func):
        """
            @ scroll_view: 滑动列表控件
            @ item_node: Item Node
            @ row_count: 每行Item个数 
            @ item_data_list: 滑动列表Item的数据
            @ create_item_func 创建Item的接口
        """
        # 列表及其数据初始化
        self._scroll_view = scroll_view
        self._scroll_view.setVisible(True)
        self._scroll_size = self._scroll_view.getContentSize()
        self._scroll_inner = self._scroll_view.getChildren()[0]
        self._scroll_inner.setAnchorPoint(cc.Vec2(0, 1))
        self._scroll_inner.setVisible(True)
        self._scroll_inner.setSwallowTouches(False)
        self._scroll_org_pos = self._scroll_inner.getPosition()

        self._item_data_list = item_data_list
        self._item_dict = {}
        self._create_item_func = create_item_func
        self.item_count = len(self._item_data_list)

        # 设置Item的参数
        self._item_node = item_node
        self._item_size = item_node.getContentSize()
        self._x_extern = self._scroll_size.width / 4.0
        self._y_extern = self._scroll_size.height / 4.0

        self.BATCH_COL = int(row_count)
        self.BATCH_ROW = int(self._scroll_size.height / self._item_size.height)
        self.BATCH_NUM = self.BATCH_ROW * self.BATCH_COL

        self._up_index = 0                    # 显示的Item上索引
        self._down_index = 2 * self.BATCH_NUM - 1   # 显示的Item下索引
        self._item_up_index = 0  # 加载的Item上索引
        self._item_down_index = -1  # 加载的Item下索引
        self._has_load_index = -1  # 已经加载过的Item的索引

        # 列表事件监听
        self.last_tick_time = time.time()
        self._scroll_view.addTouchEventListener(self._on_scroll_view)

        # Item加载参数
        self.set_loading_speed(60)
        self.loading_widget = None
        self.loading_widget_size = cc.Size(self._x_extern / 2.0, self._x_extern / 2.0)
        self.last_loading_time = 0
        self.load_ani_time = 0
        self.is_up_loading_show = False
        self.is_down_loading_show = False
        self.stop_loading_index = 0  # 惯性滑动时停止加载的位置, 仅为美观

        # 列表状态机
        self.state_machine = {
            ScrollViewAdapter.STOP: self.on_stop,
            ScrollViewAdapter.INERTIA_MOVE: self.on_inertia_move,
            ScrollViewAdapter.BOUND_MOVE: self.on_bound_move,
        }

        # 列表滑动的相关参数
        self._move_state = ScrollViewAdapter.STOP
        self._acc_cur = 1000.0              # 当前加速度
        self._acc_inertia = 6000.0          # 惯性阻力值
        self._speed_inertia = 0.0           # 当前滑行速度
        self._min_speed = 200               # 最小速度
        self._max_speed = 1500              # 最大速度
        self._move_dis = 0.0                # 回弹距离
        self._speed_rebound = self._y_extern / 0.25

        # 列表滑动模式的控制参数
        self._inertia_stop_loading_mode = False  # 是否惯性滑动停止Item加载
        self.loading_done_time = 0.25  # 加载动画的显示时长
        self._is_swallow_touch = False  # Item 是否吃点击事件

        self.touch_pos = cc.Vec2(0, 0)
        self.start_time = time.time()

    def destroy(self):
        """
            清空数据
        """
        self.loading_widget = None
        self.change_m
参数说明 listLoadingMore({id:"",id2:function(){},action:function(){},pageNum:10,getNew:undefined,funcArg:undefined,func:function(){},loadingMustTime:0,loadingDom:function(){},loadedDom:function(){},nullDataFunc:function(){},endFunc:function(){},errorFunc:function(){}}); id:滚动条id,不可以是body; id2:滚动列表的id,通过function自行根据情况返回; action:数据来源的ajax地址,插件会自动加上page和length(分别表示请求页数和当前已有记录数),返回格式统一是[{},{}...],此类jsonArray; ajaxType:ajax提交方式,将更改传递数据的方式,默认post; pageNum:每页加载数量,将会根据这个数量判断是否全部加载完成; getNew:自定义获取数据方法; funcArg:自定义获取数据时传递的参数,类型为函数,返回所需参数; childrenTag:列表子项的标签,默认LI; func:非自定义获取数据时,创建每行数据的方法; loadingMustTime:强制最小加载时间,默认0; loadingDom:加载中动画自定义,返回Dom或者HTML代码; loadedDom:完全加载完成动画自定义,返回Dom或者HTML代码; nullDataFunc:数据列表为空时执行的方法; endFunc:每页数据加载完成时执行的方法; errorFunc:ajax获取数据失败时调用的方法。 回调方法 调用本方法初始化后将会得到一个专属的方法集: Object {getNew:function,isFull:function,isRunning:function,isStop:function,loading:function,show:function}; getNew():忽略判断条件,强制执行加载操作。此时数据传递中,page值可能出错,但length值一定正确,请谨慎判断后在执行该方法; isFull(boolean):修改列表加载完成标志。true为全部加载完成,false则相反; isRunning(boolean):修改列表当前是否正在加载中标志。几乎没有使用的机会; isStop(boolean):设置是否停止加载,设置为true时将会阻止未来的所有加载操作; loading():根据当前滚动条的位置,自动判断是否需要加载新数据; show(boolean,boolean):强制设置加载中和加载完成dom的显示或隐藏,true表示显示,false相对。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值