说是自定义UI组建,其实更严格来说应该是自己写UI组建,因为这些组建都是常用的,比如Button,CheckBox,List等。
为什么要自己写呢,用别人开源的类库不就好了?何必重复造轮子?关于这类问题,我是这样理解的,首先如果不自己动手写是不会对组件的内部结构了解的一清二楚的,二是效率问题,三是方便,比用别人的更方便?对,我就是这么认为的,你要说Cocos2dX的CCS组件怎么样?至少我是觉得还有很大提升空间的,个人觉得写的比较好的组件是Flex,确实有够牛,用起来很舒服,但是效率一直都是问题,不过也能优化吧,但是自己写的东西想怎么优化就怎么优化,不是更好?而且可以做自己的UI编辑器。
Cocos2DX的点击事件做的如何?相信用过的人大部分都会觉得这是个坑。为什么,首先它没有跟显示对象关联起来,我明明设置了visible=false,确还可以点的到,明明显示对象都移除了还能点的到!实际应用中有这样的需求么? 真的是很麻烦的一件事,还有鼠标事件的层次跟显示对象的层次是分离的,明明在下面却可以先响应事件,这种设计有实际应用需求么?所以总得来说Cocos2DX坑还是挺多的,这种时候真的恨不得自己重新封装Cocos的显示列表。于是我也真的自己写了,包括CCS 组建,显示列表,事件机制,全部重写。
好吧,回到主题上。今天想分享的组件是List,整套组建系统我真的重写了不下5次了,每次的应用场景都会稍微有点不同,而且每次都会写出新东西。
List可以知道的是它的重点是显示里面的Item,什么叫Item?Item就是List的一行。当我们有大量数据的时候,当我们拖动List的时候,你是否会感觉效率比较低呢?嗯,我想大家或多或少都会遇到和感到这样的问题。
我觉得比较好的做法是一个List框最多能显示多少个Item,最多就只创建多少个Item,比如一个List高100,一个Item高20,最多能显示5个,你有100条数据,初始化的时候有5个Item在显示之中,就只创建5个Item,然后当我们下拉的时候大部分的人是把里面的内容全部换一遍,但是实际是如果原来显示的内容是0~4条数据,往下拉了一段可以显示0~5了,这个时候是创建一个新的Item并把这个新的Item的值付为第5行数据,这样最省资源(CPU,内存)。当我们继续往下拉的时候能显示1~6了,这个时候只需要替换一个,就是0的内容替换成6,然后位置重新排一下,这样是最好的效果,但是即使是flex好像也没有做到这点,如果是自定的完全可以实现这个功能。
以下贴一段List里面刷新内容的代码,供大家参考
/**
*更新列表信息内容
*
*/
public function update():void
{
var start:int;
var pos:int;
//计算首个显示显示内容的index,_pos是当前记录的整体偏移量,也就是第一个显示对象的偏移量
start = Math.floor((_posAdd==true?-1:1)*_pos/_itemHeight);
pos = _pos + (_posAdd==true?1:-1)*start*_itemHeight;
var len:int = _datas.length;
var index:int = 0;
var item:*;
//记录哪些Item是在用的,并计算需要替换哪些Item的内容即可
var useList:Vector.<CCSListItemBase> = this._items.slice(0,_items.length);
var i:int;
for(i = start; i < len; i++)
{
if(i < 0)
{
pos += (_posAdd==true?1:-1)*_itemHeight;
continue;
}
for(var c:int = 0; c < useList.length; c++)
{
if(useList[c].data == _datas[i])
{
useList.splice(c,1);
break;
}
}
pos += (_posAdd==true?1:-1)*_itemHeight;
if((_posAdd && pos >= (_vh==true?_height:_width)) || (!_posAdd && pos <= -(_vh==true?_height:_width)))
break;
}
pos = _pos + (_posAdd==true?1:-1)*start*_itemHeight;
//刷新和创建新的Item,只刷新必要的Item
for(i = start; i < len; i++)
{
item = null;
if(i < 0)
{
pos += (_posAdd==true?1:-1)*_itemHeight;
continue;
}
if(_items.length)
{
for(var f:int = 0; f < _items.length; f++)
{
if((_items[f] as CCSListItemBase).data == _datas[i])
{
item = _items[f];
break;
}
}
if(item == null && useList.length)
{
item = useList.pop();
item.setData(_datas[i]);
}
}
if(item == null)
{
item = new _itemClass();
_items.push(item);
_cliper.addChild(item);
item.setData(_datas[i]);
}
item.setVisible(true);
if(_vh)
{
if(_posAdd == false) item.setY(pos - _itemHeight);
else item.setY(pos);
}
else
{
if(_posAdd == false) item.setX(pos - _itemHeight);
else item.setX(pos);
}
pos += (_posAdd==true?1:-1)*_itemHeight;
index++;
if((_posAdd && pos >= (_vh==true?_height:_width)) || (!_posAdd && pos <= -(_vh==true?_height:_width)))
break;
}
//没有显示并且已经创建的Item设为不可见
for(i = 0; i < useList.length; i++)
{
(useList[i] as DisplayObject).setVisible(false);
}
}