Cocos2d-JS中CollectionView实现不同大小Cell同时显示的技巧(ListView中添加显示标签)

最近界面要实现一个功能:在同一个ListView中根据是否装备来展示宝石的列表,即在区分开来的两组宝石中间添加显示元素“--------------已装备的宝石-----------”,如下图。这个功能打我第一眼看到就觉得有点坑,网上并没有找到有效的答案,估计大部分是因为对问题的描述有偏差。虽然最后实现出来的时候感觉并没有多么复杂,但对于我刚入手Cocos2d-JS的一个新人来说,过程是有点艰难,因为我是一点点试验出来的。最后总结出来的无非是一些小技巧,现在分享给大家。当然,也会有更方便、快捷的方法,希望感兴趣的读者不吝赐教。


/**
 * 背包
 * Created by xj on 2016/12/22.
 */
InventoryCell = cc.TableViewCell.extend({

    m_bagCell: null,
    m_inventory: null,
    m_level: null,
    m_image: null,
    m_box: null,

    ctor: function () {
        this._super();
        this.init();
    },
    init: function () {
        if(this._super()){
            this.m_bagCell = ccs.csLoader.createNode(res.InventoryCell_Json);
            // this.m_bagCell.setAnchorPoint(0, 0);
            this.addChild(this.m_bagCell);

            this.m_level = ccui.helper.seekWidgetByName(this.m_bagCell, "label_Level");
            this.m_image = ccui.helper.seekWidgetByName(this.m_bagCell, "image_Equipment");
            this.m_box = ccui.helper.seekWidgetByName(this.m_bagCell, "ItemBox");
        }
        return true;
    },
    draw: function (ctx) {
        this._super(ctx);
    }
})

InventoryUI = BaseUI.extend({

    m_listView: null,
    m_tableView: null,
    m_items: [],
    m_cellSize: null,
    m_label_Text: null,
    m_label_Capacity: null,
    m_label_filter: null,
    m_label_meltDown: null,
    m_btnFilter: null,
    m_btnCapacity: null,
    m_btnGemChoice: null,
    m_btnTabEquipment: null,
    m_btnTabPieces: null,
    m_btnTabOther: null,
    m_btnMeltDown: null,
    m_type: 1,       //1-4:装备、**、宝石、**
    m_flag: null,
    m_gemsNoEquip: [],
    m_gemsEquiped: [],

    ctor: function () {
        BaseUI.prototype.ctor.call(this);
        this.init();
    },
    init: function () {
        if(!cc.Layer.prototype.init.call(this))
        {
            return false;
        }
        this.m_items = DataManager._Eqps.slice(0);

        var objView = ccs.csLoader.createNode(res.Inventory_Json);
        this.addChild(objView);
        this.m_cellSize = ccs.csLoader.createNode(res.InventoryCell_Json).getContentSize();
        this.m_label_Text = ccui.helper.seekWidgetByName(objView, "label_Text");
        this.m_label_Text.setString(Exceptions.TEXT_BAGCAPACITY);
        this.m_label_Capacity = ccui.helper.seekWidgetByName(objView, "label_Capacity");
        this.m_label_filter = ccui.helper.seekWidgetByName(objView, "label_Filter");
        this.m_label_meltDown = ccui.helper.seekWidgetByName(objView, "label_MeltDown");
        this.m_btnFilter = ccui.helper.seekWidgetByName(objView, "btnFilter");
        this.m_btnCapacity = ccui.helper.seekWidgetByName(objView, "btnCapacity");
        this.m_btnGemChoice = ccui.helper.seekWidgetByName(objView, "btnTabItems");
        this.m_btnTabEquipment = ccui.helper.seekWidgetByName(objView, "btnTabEquipment");
        this.m_btnTabPieces = ccui.helper.seekWidgetByName(objView, "btnTabPieces");
        this.m_btnTabOther = ccui.helper.seekWidgetByName(objView, "btnTabOther");
        this.m_btnMeltDown = ccui.helper.seekWidgetByName(objView, "btnMeltDown");

        this.m_btnFilter.addTouchEventListener(this.onButtonClick, this);
        this.m_btnCapacity.addTouchEventListener(this.onButtonClick, this);
        this.m_btnGemChoice.addTouchEventListener(this.onButtonClick, this);
        this.m_btnTabEquipment.addTouchEventListener(this.onButtonClick, this);
        this.m_btnTabPieces.addTouchEventListener(this.onButtonClick, this);
        this.m_btnTabOther.addTouchEventListener(this.onButtonClick, this);
        this.m_btnMeltDown.addTouchEventListener(this.onButtonClick, this);

        var listView = ccui.helper.seekWidgetByName(objView, "Tablelist");
        listView.setScrollBarEnabled(false);
        this.m_tableView = new cc.CollectionView(this, cc.size(listView.getContentSize().width, listView.getContentSize().height));
        this.m_tableView.setDirection(cc.SCROLLVIEW_DIRECTION_VERTICAL);
        this.m_tableView.x = listView.getPositionX();
        this.m_tableView.y = listView.getPositionY();
        this.m_tableView.setDelegate(this);
        this.addChild(this.m_tableView);

        DataManager.addObserver(this, this.updateData, cc.NOTIFICATION_LAYER_FILTER, null);
        return true;
    },
    bindData: function (data) {
        this.m_label_Capacity.setString(this.m_items.length + "/" + "100");
    },
    onButtonClick: function (sender, type) {
        switch (type){
          case ccui.Widget.TOUCH_ENDED:
              if(sender.getName() == "btnFilter")
              {
                  SceneManager.addLayer(cc.LAYER_EQUIPSELECTION);
              }
              else if(sender.getName() == "btnTabEquipment")
              {
                  this.changeItems(1);
              }
              else if(sender.getName() == "btnTabPieces")
              {
                  this.changeItems(2);
              }
              else if(sender.getName() == "btnTabItems")
              {
                  this.changeItems(3);
              }
              else if(sender.getName() == "btnTabOther")
              {
                  this.changeItems(4);
              }
              else if(sender.getName() == "btnCapacity")
              {
                  alert("额外格数");
              }
              else if(sender.getName() == "btnMeltDown")
              {
                  alert("meltDown");
              }
              break;
          default:
              break;
        }
    },
    updateData: function (sender) {
        var filters = sender.getUserData();
        this.m_items = DataManager._Eqps.slice(0);

        //根据filters[0,0,0,0,0,1]对m_items进行筛选
        //多选
        var filterItem = new Array();
        if(filters[5] != 1){    //filters[5] == 1 全选
            for(var i = 0; i < this.m_items.length; i++){
                for(var j = 0; j < 5; j++){
                    if(filters[j] == 1 && this.m_items[i].Quality == j+1){
                        filterItem.push(this.m_items[i]);
                        break;
                    }
                }
            }
            this.m_items = filterItem;
        }
        //单选
        //根据filters[0,0,0,0,0,1]对m_items进行筛选
        // var filter = 0;                                         //0-5:白绿蓝紫橙红
        // for(var i = 0; i < 6; i++){
        //     if(filters[i] == 1){
        //        filter = i;
        //        break;
        //     }
        // }
        // if(filter != 5){    //filter = 5 全选
        //     for(var i = 0; i < this.m_items.length; i++){
        //         if(this.m_items[i].Quality != filter+1){
        //             this.m_items.splice(i, 1);
        //             i --;
        //         }
        //     }
        // }

        this.m_tableView.reloadData();

    },
    changeItems: function (type) {
        if(type == 1)
        {
            this.updateButtons(true);
            this.m_items = DataManager._Eqps.slice(0);
            this.m_flag = null;
        }
        else if(type == 2)
        {
            this.updateButtons(false);
            this.m_items = DataManager._Gems.slice(0);
        }
        else if(type == 3)
        {
            this.updateButtons(false);
            var gems = DataManager._Gems.slice(0);
            this.m_gemsNoEquip = [];
            this.m_gemsEquiped = [];

            for(var i = 0; i < gems.length; i++){
                if(gems[i].Amount > 0)
                {
                    this.m_gemsNoEquip.push(gems[i]);
                }
                if(gems[i].EqpAmount > 0)
                {
                    this.m_gemsEquiped.push(gems[i]);
                }
            }
            this.m_items = this.m_gemsNoEquip.concat(this.m_gemsEquiped);

            this.addNullCell(this.m_gemsNoEquip.length);
        }
        else if(type == 4)
        {
            this.updateButtons(false);
            this.m_items = DataManager._Gems.slice(0);
        }
        this.m_type = type;
        this.m_tableView.reloadData();
    },
    updateButtons: function (display) {
        this.m_label_filter.setVisible(display);
        this.m_label_meltDown.setVisible(display);
        this.m_label_Capacity.setVisible(display);
        this.m_label_Text.setVisible(display);
        this.m_btnFilter.setVisible(display);
        this.m_btnMeltDown.setVisible(display);
        this.m_btnCapacity.setVisible(display);
    },
    selectedItemEvent: function (sender, type) {
        switch (type){
            case ccui.ListView.EVENT_SELECTED_ITEM:
                alert(sender.getCurSelectedIndex());
                break;
            default:
                break;
        }
    },
    tableCellSizeForIndex: function (table, idx) {
        if(this.m_type == 3 && (idx > this.m_flag-5 && idx <= this.m_flag))
        {
            return cc.size(110, 25);
        }
        return this.m_cellSize;
    },
    numberOfCellsInTableView: function () {
        if(!this.m_items){
            return 0;
        }
        return this.m_items.length;
    },
    cellSizeForTable: function (table) {
        return table.getContentSize();
        // return cc.size(580, 130);
    },
    tableCellAtIndex: function (table, idx) {

        var itemAtt = this.m_items[idx];
        var cell = null;
        // var cell = table.dequeueCell();
        if(!cell){
            cell = new InventoryCell();
        }
        cell.m_inventory = itemAtt;

        if(itemAtt.Id != 0){
            var pic = "";
            if(this.m_type == 1)
            {
                cell.m_level.setString("Lv." + itemAtt.Level);
                pic = "res/pic/Equip/" + itemAtt.IconId + ".png";
            }
            else if(this.m_type == 2)
            {
                cell.m_level.setString(itemAtt.Amount);
                pic = "res/pic/Gems/" + itemAtt.IconId + ".png";
            }
            else if(this.m_type == 3)
            {
                if(idx < this.m_gemsNoEquip.length)
                {
                    cell.m_level.setString(itemAtt.Amount);
                }
                else
                {
                    cell.m_level.setString(itemAtt.EqpAmount);
                }
                pic = "res/pic/Gems/" + itemAtt.IconId + ".png";
            }
            else if(this.m_type == 4)
            {
                cell.m_level.setString(itemAtt.Amount);
                pic = "res/pic/Gems/" + itemAtt.IconId + ".png";
            }
        }
        else
        {
            if(idx == this.m_flag-4)
            {
                cell = new CombatCell();
                cell._Time.setVisible(false);
                cell._Info.setString("  ------已装备宝石------")
            }
            else
            {
                cell.m_level.setVisible(false);
                cell.m_image.setVisible(false);
                cell.m_box.setVisible(false);
            }
            return cell;
        }
        this.changeNodeTexture2(pic, "image_Equipment", cell);
        return cell;
    },
    tableCellTouched: function (table, cell) {
        if(cell.m_inventory.Id != 0){
            if(this.m_type == 1)
            {
                // SceneManager.addLayer(cc.LAYER_EQUIPUI, cell.m_inventory);
                var ui = SceneManager.addLayer(cc.LAYER_EQUIPUI, null, true, cc.LAYER_ANI_NONE, true);
                if (ui)
                {
                    //替换装备与装备相关操作
                    ui.initEquipUI(null, cell.m_inventory);
                }
            }
            else if(this.m_type == 3)
            {
                SceneManager.addLayer(cc.LAYER_GEMINFO, cell.m_inventory);
            }
        }
    },
    addNullCell: function (index) {
        //添加空Cell
        var flag = index % 5 == 0 ? index+5 : 5 * (parseInt(index/5) + 2);
        var nullCell = new GemAtt();
        //从索引处开始添加空元素
        for(var i=index; i<flag; i++)
        {
            this.m_items.splice(i, 0, nullCell);
            if(i == flag-1)
            {
                this.m_flag = i;
            }
        }
    }
});

InventoryUI.create = function () {
    return new InventoryUI();
}


思路解析:

把整理好的没有装备的宝石和已经装备好的宝石数组放入同一数组中,使其前一部分全为没有装备的宝石,后一部分则为装备的宝石。根据分界线的索引,即没有装备宝石的数组的length属性,为整合好的数组添加没有实际意义的Cell,把它看作填空Cell,使得填空后的数组满足:当未装备的宝石数量不为每行所能含有Cell的个数的整数倍时,最后一行填充空的Cell。以让用户感觉后边没有元素了。比如:CollectView每行可容纳5个Cell,当未装备的宝石为8个时,需要在会后一行,填充两个空的Cell。此时做到可以把装备与否的宝石区分开来。在此基础上,再添加每行容纳Cell个数的空Cell,即可将要求中的提示信息“--------已装备宝石----------”留出空间来。最后处理留出空间的高度显示。

关键代码解析:

1、行数:196-212

            var gems = DataManager._Gems.slice(0);
            this.m_gemsNoEquip = [];
            this.m_gemsEquiped = [];

            for(var i = 0; i < gems.length; i++){
                if(gems[i].Amount > 0)
                {
                    this.m_gemsNoEquip.push(gems[i]);
                }
                if(gems[i].EqpAmount > 0)
                {
                    this.m_gemsEquiped.push(gems[i]);
                }
            }
            this.m_items = this.m_gemsNoEquip.concat(this.m_gemsEquiped);

            this.addNullCell(this.m_gemsNoEquip.length);

将拿到的宝石结构,分成没有装备和已经装备的两个数组,m_gemsNoEquip和m_gemsEquiped;并通过concat方法将两个数组合成一个新的数组,之后执行addNullCell()方法,为整合好的数组,添加空Cell个数;

2、行数:334-347

    addNullCell: function (index) {
        //添加空Cell
        var flag = index % 5 == 0 ? index+5 : 5 * (parseInt(index/5) + 2);
        var nullCell = new GemAtt();
        //从索引处开始添加空元素
        for(var i=index; i<flag; i++)
        {
            this.m_items.splice(i, 0, nullCell);
            if(i == flag-1)
            {
                this.m_flag = i;
            }
        }
    }

此为addNullCell()的方法,此方法在为数组添加填充Cell的同时,在344行标记了最后一个空Cell元素的索引,这个索引将是一个关键;

3、行数:240-246

    tableCellSizeForIndex: function (table, idx) {
        if(this.m_type == 3 && (idx > this.m_flag-5 && idx <= this.m_flag))
        {
            return cc.size(110, 25);
        }
        return this.m_cellSize;
    },
根据索引值,将整合的数组中整行为空的高度设置成需要的数值,如:正常Cell的高度是130,此处将空行设置为25;

4、行号:299-311

            if(idx == this.m_flag-4)
            {
                cell = new CombatCell();
                cell._Time.setVisible(false);
                cell._Info.setString("  ------已装备宝石------")
            }
            else
            {
                cell.m_level.setVisible(false);
                cell.m_image.setVisible(false);
                cell.m_box.setVisible(false);
            }
            return cell;
tableCellAtIndex中,如果检测到是数组中的填充数据,那么可以把此处的cell替换成其他cell,此处用了一个高度较低,宽度较长的适合显示的Cell。至于为什么idx==this.m_flag-4,这个位置根据具体情况设置。从代码中可以看出其实填充Cell就是把普通Cell的控件设置成不可见。

实现效果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轩小川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值