Flex 对ArrayCollection的重构
由于项目的需要,对ArrayCollection进行重构,包括如下功能:
1,排序
2,moveFirst moveLast moveNext movePre 进行记录导航 和选择某个index的对象
3,删除,更新,插入,添加记录的功能
4,过滤
以下是例子:
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init();">
- <mx:Script>
- <![CDATA[
- import mx.collections.CursorBookmark;
- import com.hexagonstar.util.debug.Debug;
- import org.app.utils.common.collections.MyArrayCollection;
- import com.adobe.serialization.json.JSON;
- var arr:Array=[
- {a:1,b:1,c:1},
- {a:21,b:21,c:21},
- {a:12,b:12,c:12},
- {a:10,b:10,c:10},
- {a:2,b:2,c:2}
- ];
- [Bindable]
- var coll:MyArrayCollection = null;
- [Bindable]
- var scc:String = null;
- private function init():void{
- coll =new MyArrayCollection(arr);
- //var sortArr:Array=[{name:"a"},{name:"b"}];
- //coll.sortCollection(sortArr);
- src.text= coll.toString();
- //dest.text = JSON.encode(coll.currentItem);
- scc = coll.toString();
- dest.text = scc;
- //keywords
- coll.keywords=["a"];
- }
- private function insert():void{
- var s:String = src.text;
- var o:Object = JSON.decode(s);
- coll.insertItem(o);
- scc = coll.toString();
- dest.text = scc;
- }
- private function append():void{
- var s:String = src.text;
- var o:Object = JSON.decode(s);
- coll.appendItem(o);
- scc = coll.toString();
- dest.text = scc;
- }
- private function moveFirst():void{
- var o:Object = coll.moveFirst();
- dest.text = JSON.encode(o);
- }
- private function moveLast():void{
- var o:Object = coll.moveLast();
- dest.text = JSON.encode(o);
- }
- private function moveNext():void{
- var o:Object = coll.moveNext();
- dest.text = JSON.encode(o);
- }
- private function movePre():void{
- var o:Object = coll.movePrevious();
- dest.text = JSON.encode(o);
- }
- private function doClear():void{
- dest.text = "";
- }
- private function doUpd():void{
- var o:Object = JSON.decode(src.text);
- coll.updateItem(o);
- o = coll.currentItem;
- dest.text = JSON.encode(o);
- }
- private function doDel():void{
- var o:Object = JSON.decode(src.text);
- var flg:Boolean = coll.remove();
- Debug.trace("--remove:"+flg);
- scc = coll.toString();
- dest.text = scc;
- }
- ]]>
- </mx:Script>
- <mx:TextArea id="src" x="25" y="40" width="267" height="103"/>
- <mx:Button x="25" y="10" label="更新" click="doUpd();"/>
- <mx:Button x="188" y="10" label="删除" click="doDel();"/>
- <mx:Button x="244" y="10" label="排序"/>
- <mx:Button x="76" y="10" label="插入" click="insert();"/>
- <mx:Button x="132" y="10" label="添加" click="append();"/>
- <mx:TextArea id="dest" x="300" y="40" width="333" height="103" editable="false" text="{scc}"/>
- <mx:Button x="25" y="299" label="|<" toolTip="第一个" click="moveFirst();"/>
- <mx:Button x="125" y="299" label=">>" toolTip="后一个" click="moveNext();"/>
- <mx:Button x="73" y="299" label="<<" toolTip="前一个" click="movePre();"/>
- <mx:Button x="177" y="299" label=">|" toolTip="最后一个" click="moveLast();"/>
- <mx:DataGrid x="25" y="151" width="608" height="143" dataProvider="{coll}">
- <mx:columns>
- <mx:DataGridColumn headerText="ColumnA" dataField="a"/>
- <mx:DataGridColumn headerText="ColumnB" dataField="b"/>
- <mx:DataGridColumn headerText="ColumnC" dataField="c"/>
- </mx:columns>
- </mx:DataGrid>
- <mx:Button x="585" y="10" label="清空" toggle="true" click="doClear();"/>
- </mx:Application>
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init();"> <mx:Script> <![CDATA[ import mx.collections.CursorBookmark; import com.hexagonstar.util.debug.Debug; import org.app.utils.common.collections.MyArrayCollection; import com.adobe.serialization.json.JSON; var arr:Array=[ {a:1,b:1,c:1}, {a:21,b:21,c:21}, {a:12,b:12,c:12}, {a:10,b:10,c:10}, {a:2,b:2,c:2} ]; [Bindable] var coll:MyArrayCollection = null; [Bindable] var scc:String = null; private function init():void{ coll =new MyArrayCollection(arr); //var sortArr:Array=[{name:"a"},{name:"b"}]; //coll.sortCollection(sortArr); src.text= coll.toString(); //dest.text = JSON.encode(coll.currentItem); scc = coll.toString(); dest.text = scc; //keywords coll.keywords=["a"]; } private function insert():void{ var s:String = src.text; var o:Object = JSON.decode(s); coll.insertItem(o); scc = coll.toString(); dest.text = scc; } private function append():void{ var s:String = src.text; var o:Object = JSON.decode(s); coll.appendItem(o); scc = coll.toString(); dest.text = scc; } private function moveFirst():void{ var o:Object = coll.moveFirst(); dest.text = JSON.encode(o); } private function moveLast():void{ var o:Object = coll.moveLast(); dest.text = JSON.encode(o); } private function moveNext():void{ var o:Object = coll.moveNext(); dest.text = JSON.encode(o); } private function movePre():void{ var o:Object = coll.movePrevious(); dest.text = JSON.encode(o); } private function doClear():void{ dest.text = ""; } private function doUpd():void{ var o:Object = JSON.decode(src.text); coll.updateItem(o); o = coll.currentItem; dest.text = JSON.encode(o); } private function doDel():void{ var o:Object = JSON.decode(src.text); var flg:Boolean = coll.remove(); Debug.trace("--remove:"+flg); scc = coll.toString(); dest.text = scc; } ]]> </mx:Script> <mx:TextArea id="src" x="25" y="40" width="267" height="103"/> <mx:Button x="25" y="10" label="更新" click="doUpd();"/> <mx:Button x="188" y="10" label="删除" click="doDel();"/> <mx:Button x="244" y="10" label="排序"/> <mx:Button x="76" y="10" label="插入" click="insert();"/> <mx:Button x="132" y="10" label="添加" click="append();"/> <mx:TextArea id="dest" x="300" y="40" width="333" height="103" editable="false" text="{scc}"/> <mx:Button x="25" y="299" label="|<" toolTip="第一个" click="moveFirst();"/> <mx:Button x="125" y="299" label=">>" toolTip="后一个" click="moveNext();"/> <mx:Button x="73" y="299" label="<<" toolTip="前一个" click="movePre();"/> <mx:Button x="177" y="299" label=">|" toolTip="最后一个" click="moveLast();"/> <mx:DataGrid x="25" y="151" width="608" height="143" dataProvider="{coll}"> <mx:columns> <mx:DataGridColumn headerText="ColumnA" dataField="a"/> <mx:DataGridColumn headerText="ColumnB" dataField="b"/> <mx:DataGridColumn headerText="ColumnC" dataField="c"/> </mx:columns> </mx:DataGrid> <mx:Button x="585" y="10" label="清空" toggle="true" click="doClear();"/> </mx:Application>
以下是源码:
- /**
- * 用法:
- * coll=new ArrayCollection(
- * [
- * {name: "Martin Foo", age: 25},
- * {name: "Joe Bar", age: 15},
- * {name: "John Baz", age: 23}
- * ]
- * );
- * coll.addItemAt({name: "James Fez", age: 40}, 0);
- */
- package org.app.utils.common.collections
- {
- import flash.events.Event;
- import mx.collections.ArrayCollection;
- import mx.collections.CursorBookmark;
- import mx.collections.IViewCursor;
- import mx.collections.Sort;
- import mx.collections.SortField;
- import mx.events.FlexEvent;
- import mx.logging.ILogger;
- import org.app.framework.AppContext;
- import org.app.utils.common.MyJSONUtils;
- import org.app.utils.log.MyLoggerManager;
- public class MyArrayCollection extends ArrayCollection
- {
- ////////////////////////////////////////////////////////////////////////
- /*排序规则参数*/
- public static const RL_NAME:String = "name";//要排序的字段的名称。[String]
- public static const RL_CASEINSENSITIVE:String = "caseInsensitive";//Boolean 指定此字段的排序是否应不区分大小写。
- public static const RL_DESCENDING:String = "descending";//Boolean 指定此字段是否应按降序排序。
- /*事件相关*/
- //光标位置更新时的事件
- public static const EVENT_CURSOR_UPDATE:String = "event_cursor_update";
- /*Object 指定当要进行排序的字段包含数值 (number/int/uint)
- * 或数值的字符串表示形式时,比较运算符是否使用数值比较。*/
- public static const RL_NUMERIC:String = "numeric";
- ////////////////////////////////////////////////////////////////////////
- private var logger:ILogger = MyLoggerManager.getLogger("MyArrayCollection",AppContext.getInstance().appLogTarget);
- ////////////////////////////////////////////////////////////////////////
- /*游标*/
- private var _cursor:IViewCursor = null;//当前游标
- private var _currentItem:Object = null;//当前游标指向对象
- /*如果是JSON对象,那么有keys*/
- private var _keys:Array = null;//该数组包含的json properties
- private var _keywords:Array = null;//哪些properties是主键,用于判断重复
- public function MyArrayCollection(source:Array=null)
- {
- super(source);
- //取得当前的光标对象
- this._cursor = this.createCursor();
- //注册光标位置更新事件
- this._cursor.addEventListener(FlexEvent.CURSOR_UPDATE,fireCursorUpdate,false,0,true);
- //給当前光标对象赋值--就会触发cursor update事件
- this._cursor.seek(CursorBookmark.CURRENT);
- //初始化keys 或者 获取keys
- this.fetchKeys();
- }
- ////////////////////////////////////////////////////////////////////////
- /**
- * 当光标位置更新时触发的事件,在这取得当前光标位置的值,
- * 其他地方光标移动时不要給 currentItem赋值了。
- * @param FlexEvent
- * @return
- */
- private function fireCursorUpdate(event:FlexEvent):void{
- //取得当前的值
- this._currentItem = (event.currentTarget as IViewCursor).current;
- //防止 moveLast moveFirst抛出多2个事件,只有当前有对象值了,才抛出
- var a:String = "不抛出";
- if (this._currentItem) {
- a="抛出";
- this.dispatchEvent(new Event(EVENT_CURSOR_UPDATE));
- }
- var s:String = MyJSONUtils.encode(this._currentItem);
- logger.debug("--触发了 cursor update 事件,当前对象:"+s+"["+a+"]");
- }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- public function set cursor(cursor:IViewCursor):void{
- this._cursor = cursor;
- }
- public function get cursor():IViewCursor{
- return this._cursor;
- }
- public function set currentItem(o:Object):void{
- //替换掉当前对象里面的值
- this.updateItem(o);
- //this._currentItem = o;
- }
- public function get currentItem():Object{
- return this._currentItem;
- }
- ////////////////////////////////////////////////////////////////////////
- public function fetchKeys():void{
- if(this.length>0){
- var o:Object = this.getItemAt(0);
- this._keys = MyJSONUtils.fetchKeys(o);
- }else{
- this._keys = [];
- }
- }
- public function getKeys():Array{
- if(this._keys.length<=0){
- this.fetchKeys();
- }
- return this._keys;
- }
- public function set keywords(k:Array):void{
- this._keywords = k;
- }
- public function get keywords():Array{
- return this._keywords;
- }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- /**
- * 检查是否存在某个条件的对象??????
- * @param Object json object eg:{name:"xxx_name", age:34 .....}
- * @param String 比较类型 采用Sort里面引用的常量
- * @return int 存在的个数
- *
- * @see mx.collections.Sort
- */
- public function checkExist(conditionObj:Object,mode:String=Sort.ANY_INDEX_MODE):int{
- var sort:Sort = new Sort();
- return sort.findItem(this.source,conditionObj,mode);
- }
- /**
- * [这个比较 很慢]
- * 检查是否存在某个对象,其中keys指根据哪些key进行比较,如果为空,那么根据全部key来比
- * @param Object
- * @param Array 要比较的key
- * @return Boolean true存在
- */
- public function isExist(o:Object,keys:Array=null):Boolean{
- var key1:Array = keys;
- if(key1==null){
- key1 = MyJSONUtils.fetchKeys(o);
- }
- var item1:String = null;
- var l:int=key1.length;
- for each(var obj:Object in this){
- var flg:int = 0;
- for(var i:int=0;i<l;i++){
- item1=key1[i];
- if(o[item1]==obj[item1]){
- flg++;
- }
- }
- if(flg==l)return true;
- }
- return false;
- }
- /**
- * 覆盖该方法,来做重复检查
- * @param Object 要比较的对象
- * @return Boolean true存在
- */
- override public function contains(item:Object):Boolean{
- return isExist(item,this._keywords);
- }
- ////////////////////////////////////////////////////////////////////////
- /**
- * 按照一定的规则排序,可以多个字段同时排序:
- * -- name : String 要排序的字段的名称。
- * -- caseInsensitive : Boolean 指定此字段的排序是否应不区分大小写。
- * -- descending : Boolean 指定此字段是否应按降序排序。
- * -- numeric : Object 指定当要进行排序的字段包含数值 (number/int/uint)
- * 或数值的字符串表示形式时,比较运算符是否使用数值比较。
- * eg:[{name:'age',caseInsensitive:true,descending:false,numeric:null},
- * {name:'age',descending:false}...]
- * 是个数组,而且 里面是json对象,包含四个元素:name,caseInsensitive,descending,numeric,
- * 其中,name是必须的,其他的可选。
- * @param Object 类似上面的写
- * @return
- * @see mx.colloections.SortField
- *
- */
- public function sortCollection(conditionObj:Array):void{
- var leng:int = conditionObj.length;
- var fields:Array = [];
- var sortField:SortField = null;
- var o:Object=null;
- var name:String=null;
- var caseInsensitive:Boolean=false;
- var descending:Boolean = false;
- var numeric:Object = null;
- for(var i:int=0;i<leng;i++){
- o = conditionObj[i];
- sortField = new SortField();
- //加入参数
- sortField.name=o[MyArrayCollection.RL_NAME];
- var tmp:Object = o[MyArrayCollection.RL_CASEINSENSITIVE];
- caseInsensitive=tmp==null?false:true;
- sortField.caseInsensitive=caseInsensitive;
- tmp = o[MyArrayCollection.RL_DESCENDING];
- descending=tmp==null?false:true;
- sortField.descending=descending;
- tmp = o[MyArrayCollection.RL_NUMERIC];
- numeric=tmp==null?null:tmp;
- sortField.numeric=numeric;
- //加入比较器
- fields.push(sortField);
- }
- var sort:Sort = new Sort();
- sort.fields=fields;
- this.sort = sort;
- this.refresh();
- }
- ////////////////////////////////////////////////////////////////////////
- /**
- * 过滤,首先必须知道自己要过滤的集合里面有些什么字段,
- * coll = new ArrayCollection([
- * {name:"Martin Foo", age:25},
- * {name:"Joe Bar", age:15},
- * {name:"John Baz", age:23},
- * {name:"Matt Baz", age:21}]);
- * 那么func:
- * private function filterFunc(value:Object):Object {
- * if(Number(value.age) > 21) {
- * return true;
- * }
- * return false;
- *}
- * @param Function 如上
- * @return
- */
- public function filterCollection(filterFunc:Function):void{
- this.filterFunction = filterFunc;
- this.refresh();
- }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- /**
- * 取得第一个对象,根据cursorMove 来判断是否移动光标
- * @param Boolean 是否移动当前光标
- * @return Object 第一个位置的对象
- */
- public function firstItem(cursorMove:Boolean=true):Object{
- if(cursorMove){
- return this.moveFirst();
- }
- return this.getItemAt(0);
- }
- /**
- * 取得最后一个对象,根据cursorMove 来判断是否移动光标
- * @param Boolean 是否移动当前光标
- * @return Object 最后一个位置的对象
- */
- public function lastItem(cursorMove:Boolean=true):Object{
- if(cursorMove){
- return this.moveLast();
- }
- return this.getItemAt(this.length-1);
- }
- /**
- * 在最后位置插入对象,会检查是否存在相同的对象.
- * @param Object
- * @return Boolean true成功 false失败
- */
- public function appendItem(o:Object):Boolean{
- //该方法检查每个元素都相同
- var exist:Boolean= this.contains(o);
- if(!exist){
- this.addItem(o);
- //当前游标处理
- this.moveCursorTo(o);
- if(this._currentItem){
- return true;
- }
- }
- return false;
- }
- /**
- * 在当前位置插入一个对象
- * @param Object
- * @return Boolean
- */
- public function insertItem(o:Object):Boolean{
- //该方法检查每个元素都相同
- var exist:Boolean= this.contains(o);
- if(!exist){
- this._cursor.insert(o);
- //当前游标处理
- this.moveCursorTo(o);
- if(this._currentItem){
- return true;
- }
- }
- return false;
- }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- /**
- * 删除当前光标指向的对象,并选择下一个对象,如果下一个对象为空,那么选择最后一个
- * @return Object 当前被删除的对象
- *
- */
- public function remove():Object {
- var o:Object=this._cursor.remove();
- if (!this._currentItem) {
- this._cursor.movePrevious();
- }
- return o;
- }
- /**
- * 删除指定的对象
- * @param Object
- * @return Boolean true成功
- */
- public function removeItem(o:Object):Boolean{
- this.moveCursorTo(o);
- var o:Object = this.remove();
- if(o)return true;
- return false;
- }
- /**
- * 删除所有数据
- */
- override public function removeAll():void{
- super.removeAll();
- this.source = [];
- }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- /**
- * 更新当前光标指向的对象
- * @param Object 新的对象
- * @return
- */
- public function updateItem(o:Object):void{
- var keys:Array = MyJSONUtils.fetchKeys(o);
- var l:int = keys.length;
- var key:String=null;
- for(var i:int=0;i<l;i++){
- key = keys[i];
- if(this._currentItem[key]){
- this._currentItem[key]=o[key];
- this.itemUpdated(this._currentItem);//这个会令ui更新
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- /**
- * 把光标移到指定的对象上,
- * @param Object 目标对象
- * @return Object 当前选择的对象
- */
- public function moveCursorTo(o:Object):Object {
- //当前游标处理
- var index:int=this.getItemIndex(o);
- return this.moveCursorByIndex(index);
- }
- public function moveCursorByIndex(index:int):Object{
- if(index < 0 || index >= this.length)return null;
- var oldIndex:int = this.getItemIndex(this._currentItem);
- var offset:int = 0;
- if (oldIndex > index) {
- offset = -(oldIndex - index);
- } else if (oldIndex < index) {
- offset = index - oldIndex;
- }
- this._cursor.seek(this._cursor.bookmark, offset);
- return this._currentItem;
- }
- /**
- * 光标指向第一个位置,返回第一个位置的值
- * @return Object 当前光标位置的对象
- */
- public function moveFirst():Object{
- //当前游标处理
- this._cursor.seek(CursorBookmark.FIRST);
- //当前对象设置值
- //在cursor update 事件里面处理了
- //返回当前对象
- return this._currentItem;
- }
- /**
- * 光标指向最后一个位置,返回最后一个位置的值
- * @return Object 当前光标位置的对象
- */
- public function moveLast():Object{
- //当前游标处理
- this._cursor.seek(CursorBookmark.LAST);
- //当前对象设置值
- //在cursor update 事件里面处理了
- //返回当前对象
- return this._currentItem;
- }
- /**
- * 光标指向下一个位置,返回光标指向位置的对象
- * @return Object 当前光标位置的对象
- */
- public function moveNext():Object {
- if (!this._cursor.afterLast) {
- this._cursor.moveNext();
- //this._currentItem = this._cursor.current;
- if (!this._currentItem) {
- this._cursor.movePrevious();
- }
- }
- return this._currentItem;
- }
- /**
- * 光标指向上一个位置,返回光标指向位置的对象
- * @return Object 当前光标位置的对象
- */
- public function movePrevious():Object {
- if (!this._cursor.beforeFirst) {
- this._cursor.movePrevious();
- if (!this._currentItem) {
- this._cursor.moveNext();
- }
- }
- return this._currentItem;
- }
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- /**
- * 把值转成字符串
- * @return String
- */
- override public function toString():String{
- var s:String = "";
- var l:int=this.length;
- for(var i:int=0;i<l;i++){
- s+=MyJSONUtils.encode(this.getItemAt(i));
- }
- return s;
- }
- }//end class
- }//end package