• ‎Cocos2d-x 学习笔记(22) TableView


    【Cocos2d-x 学习笔记 】目录

    1. 简介

    TableView直接继承了ScrollView和ScrollViewDelegate。说明TableView能实现ScrollView拖动container的效果。重写了ScrollViewDelegate的委托方法scrollViewDidScroll,对ScrollView功能进行“拓展”。

    TableView和ScrollView都能够在可视范围内拖动container,在可视范围内展示部分的container,但是两者也有明显的不同。

    ScrollView是一次性将要展示的所有元素加到container,可视范围只是在其中选取一部分显示。

    TableView是对container内的cell“动态加载”,当cell需要出现在可视范围的时候再把cell加到container,cell离开可视范围则把cell缓存。TableView的“动态加载”需要ScrollView委托的scrollViewDidScroll方法实时监测可视范围内cell的变化情况。

    ScrollView可以不限方向拖动和缩放。TableView只能拖动,且拖动方向限制为纵向或横向。

    2. TableViewCell

    TableView的container是“动态加载”“动态删除”。所谓“动态”依赖着container的基本单位cell,“加载”“删除”指的是对cell的操作。

    TableViewCell直接继承Node。

    cell有成员变量idx,是cell的下标或者序号,用来识别cell。idx为-1时表明该cell处于无效状态,此时cell并没有在可视范围呈现,而是进行缓存。

    我们通过对cell增加Sprite Label等子节点,让cell有了图像和文本等效果。

    cell按序排列就成为了container。

    3. TableViewDataSource TableViewDelegate

    有TableView对象的Layer等都要直接继承TableViewDataSource和TableViewDelegate,根据需要可以重写这些方法。

    TableViewDataSource是供我们自定义TableView相关数据处理方法的类,该类中的方法需要我们重写。

    virtual Size tableCellSizeForIndex(TableView* table, ssize_t idx); //根据idx返回cell的size
    virtual Size cellSizeForTable(TableView* table); //返回cell的size
    virtual TableViewCell* tableCellAtIndex(TableView *table, ssize_t idx) = 0; //根据idx返回cell
    virtual ssize_t numberOfCellsInTableView(TableView *table) = 0; //返回cell总数

    TableViewDelegate委托类直接继承ScrollViewDelegate。

    virtual void tableCellTouched(TableView* table, TableViewCell* cell) = 0;
    virtual void tableCellHighlight(TableView* table, TableViewCell* cell);
    virtual void tableCellUnhighlight(TableView* table, TableViewCell* cell);
    virtual void tableCellWillRecycle(TableView* table, TableViewCell* cell);

    4. 部分属性

    - TableViewCell *_touchedCell

    在Touch事件3个回调函数中使用到,指的是当前触摸到的cell。我们可以对当前触摸的cell进行处理。

    - VerticalFillOrder _vordering

    纵向排列顺序的枚举VerticalFillOrder包含从小到大TOP_DOWN,从大到小BOTTOM_UP。

    - std::set<ssize_t>* _indices

    可视idx容器,存储可视范围内cell的idx。

    - std::vector<float> _vCellsPositions

    通过_updateCellPositions方法,根据我们对cell数量的设置和size的设置,计算每个cell起始点x或y并储存到该容器。容器最后多余一个位置,存储container的长度。

    - Vector<TableViewCell*> _cellsUsed

    可视容器。存储可视区域内cell的容器。

    - Vector<TableViewCell*> _cellsFreed

    缓存容器。存储离开可视区域内cell的容器,按队列形式存储。这些cell的idx被置-1,表明无效cell。

    - TableViewDataSource* _dataSource

    - TableViewDelegate* _tableViewDelegate

    两个委托类。

    - Direction _oldDirection

    和_direction搭配使用,在构造函数和reloadData方法开始时设为NONE,用于设置container的初始位置

    - bool _isUsedCellsDirty

    脏标记,用于给可视容器按idx重新排序。可视容器cell数量发生变化时会置true。

    5. 主要方法

    - create(TableViewDataSource* dataSource, Size size, Node *container)

    设置了默认排列方式BOTTOM_UP,方向VERTICAL。

    调用了_updateCellPositions方法:设置容器_vCellsPositions。

    调用了_updateContentSize方法:设置container大小,长度为所有cell之和;设置container的位置。

    执行的setDelegate方法,将this设为了_delegate。

    - reloadData()

    重新加载TableView,相当于刷新一次TableView。包括清空可视容器和可视idx容器,cell存入缓存容器,更新_vCellsPositions,重新设置container大小和位置,执行scrollViewDidScroll更新可视范围cell的状态。

    在执行setVerticalFillOrder方法设置新的纵向排列顺序之后,会执行该方法。

    - cellAtIndex(ssize_t idx)

    根据idx返回cell。idx和cell必须在可视idx容器和可视容器中,即cell必须在可视范围内,无效cell不会被返回。

    - scrollViewDidScroll(ScrollView* view)

    该方法用于更新可视范围内cell的状态。

    该方法在设置container位置的setContentOffset和reloadData会被调用

    create执行的setDelegate方法,将this设为了_delegate,从而实现了setContentOffset方法执行时会调用该方法更新cell。

    主要逻辑是:

    1. 判断脏标记_isUsedCellsDirty。为true时要对可视容器_cellsUsed内的cell按idx从小到大排序。TableView的cell是有序排列的。

    2. 计算offset。该坐标offset把container的坐标乘-1,即“container相对可视范围的位置”转换成“可视范围相对container的位置”。

    转换的原因是,我们之后需要计算可视范围cell的idx,而cell是按顺序排列在container中。通过可视范围相对container的位置,就能很容易理解并且计算当前可视范围内cell的idx了。

    3. 计算可视范围内cell最小的idx(startIdx)和最大的idx(endIdx)。该范围内的cell正出现在可视区域内。

    4. 越界处理,即“删除”从可视范围内离开的cell。

    可视容器_cellsUsed不为空时,容器内的cell已经按idx从小到大排序,所以判断是分别从容器第一个和最后一个cell开始,判断idx与startIdx或endIdx的关系。如果需要“删除”,则执行_moveCellOutOfSight方法进行“删除”,并继续判断下一个idx,直到所有可视容器内的cell idx都在范围之中。

    5. 新cell的处理。

    没有新cell时,可视范围内的idx和存储可视cell idx的容器_indices显然是一一对应。当出现新cell,其idx一定不在可视idx容器_indices之中,需要执行updateCellAtIndex方法,添加该cell的信息到容器中。

    -  _moveCellOutOfSight(TableViewCell *cell)

    该方法是对离开可视区域内的cell进行删除和缓存。

    scrollViewDidScroll需要检测当前cell

    主要逻辑是:

    1. 调用delegate的tableCellWillRecycle方法。该委托方法

    2. 对参数cell进行以下操作:

      加入到缓存容器_cellsFreed;

      从可视容器_cellsUsed删除;

      其idx从可视下标容器_indices删除;

      其idx置-1;

      container删除该子节点cell。

    - _indexFromOffset(Vec2 offset)

    根据坐标求出cell的下标。根据坐标在容器_vCellsPositions中进行二分查找,确定坐标对应的下标。

    - _offsetFromIndex(ssize_t index)

    根据cell序号返回坐标。通过序号和_vCellsPositions序号一一对应的关系,返回坐标值。

    在_setIndexForCell方法中,根据index给cell设置位置时,需要通过该方法计算位置。

    - updateCellAtIndex(ssize_t idx)

    该方法用于对新出现在可视范围内的cell,更新容器的相关信息。

    该方法只在scrollViewDidScroll方法监测到新cell出现时才会被调用。

    主要逻辑是:

    1. 生成参数idx对应的cell。

    调用了dataSource的tableCellAtIndex方法,该方法需要被重写。

    在Cocos2dx官方Demo中,tableCellAtIndex主要逻辑是:执行dequeueCell方法。尝试从缓存容器_cellsFreed中弹出第一个cell。如果缓存容器中没有cell,则新建cell。如果弹出了cell,该cell作为生成的cell。当然,无论是不是新cell,cell显示的下标idx都需要改为参数idx。

    2. 设置cell的idx和位置。执行的是_setIndexForCell方法。

    3. 把cell加入到TableView中:cell作为container的子节点。cell加入可视容器_cellsUsed。idx加入可视idx容器_indices。置脏标记,用于对可视容器重新排序。

    6. Touch事件的3个回调函数

    - onTouchBegan

    1. TableView存在不可见的父节点时,返回false。

    2. 执行父类ScrollView的onTouchBegan方法,保存Touch信息,返回值作为TableView的该方法返回值。

    3. 是单点触摸时,通过触摸点坐标计算出当前触摸了哪个cell。如果cell存在,执行delegate的tableCellHighlight方法,可以对cell执行高亮等操作。

    4. 是两点触摸且存在正在触摸的cell(_touchedCell)时,执行delegate的tableCellUnhighlight方法,可以取消该cell的高亮。然后_touchedCell置空。

    - onTouchMoved

    1. 执行父类ScrollView的onTouchMoved方法,对container进行拖动。

    2. 如果拖动时存在_touchedCell,执行delegate的tableCellUnhighlight方法,可以取消该cell的高亮。然后_touchedCell置空。

    - onTouchEnded

    1. 如果存在_touchedCell,且触摸结束点在可视范围内,执行delegate的tableCellUnhighlight和tableCellTouched方法。

    正常情况下,_touchedCell在onTouchMoved方法应该置空,仍存在时,说明onTouchMoved时移动距离过小。

    2. 执行父类ScrollView的onTouchEnded方法。


    本文地址:https://www.cnblogs.com/deepcho/p/cocos2dx-tableview.html

  • 相关阅读:
    Java基础——链表的添加、移除、反转
    Java基础——数组队列的原理和实现
    Java基础——String、StringBuiler、StringBuffer的用法和区别
    Java基础——解决JFrame.setBackground设置无效,mac系统IDEA编译器
    Java基础——文件查找创建删除
    Java基础——Java异常机制
    线性表的操作
    Linux目录及文件系统操作
    Linux用户及文件权限管理
    Linux日志系统
  • 原文地址:https://www.cnblogs.com/deepcho/p/cocos2dx-tableview.html
Copyright © 2020-2023  润新知