动态加载滑动列表
采用了类似分片加载的策略,仅加载出当前可以看到的图片以及一定的预加载部分,随着滑动逐渐的加载出下边的内容,但大量的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