Laya 实现带有子菜单的List

Laya 用List实现固定大小的二级菜单

@ixenos 2020-10-29 11:19:38

1.继承修改了List

  1     /**
  2      * 改良List
  3      * 改良目标:单列列表,item不规则大小
  4      * 
  5      * @author ixenos 2020-10-27 14:40:00 
  6      * 
  7      */
  8     public class CList extends List
  9     {
 10         /**单元格渲染定位处理器(默认返回参数 _isVertical:Boolean,cell:Box,pos:Number,index:int)*/
 11         public var posHandler:Handler;
 12         /**数据单元位置缓存,设计给单列列表使用,多列列表再斟酌一下*/
 13         private var posCache:Array = [];
 14         
 15         public function CList()
 16         {
 17             super();
 18         }
 19         
 20         /**
 21          * 渲染一个单元格。
 22          * @param cell 需要渲染的单元格对象。
 23          * @param index 单元格索引。
 24          */
 25         override protected function renderItem(cell:*, index:int):void {
 26             if (_array && index >= 0 && index < _array.length) {
 27                 cell.visible = true;
 28                 
 29                 if (cell._$bindData) {
 30                     cell._dataSource = _array[index];
 31                     _bindData(cell, _array[index]);
 32                 } else cell.dataSource = _array[index];
 33                 
 34                 if (!cacheContent) {
 35                     //TODO:
 36                     posCell(cell, index);
 37                 }
 38                 if (hasListener(Event.RENDER)) event(Event.RENDER, [cell, index]);
 39                 if (renderHandler) renderHandler.runWith([cell, index]);
 40             } else {
 41                 cell.visible = false;
 42                 cell.dataSource = null;
 43             }
 44         }
 45 
 46         /**
 47          * @private
 48          * 滚动条的 <code>Event.CHANGE</code> 事件侦听处理函数。
 49          */
 50         override protected function onScrollBarChange(e:Event = null):void {
 51             runCallLater(changeCells);
 52             var scrollValue:Number = _scrollBar.value;
 53             var lineX:int = (_isVertical ? this.repeatX : this.repeatY);
 54             var lineY:int = (_isVertical ? this.repeatY : this.repeatX);
 55             var scrollLine:int = Math.floor(scrollValue / _cellSize);
 56             
 57             //CList: 增加序号精度, 仅限用于单列列表 --ixenos 2020-10-28 09:47:22
 58             if(posCache && posCache.length>0){
 59                 for (var j:int = 0; j < posCache.length; j++) {
 60                     var pos:Number = posCache[j];
 61                     var lastPos:Number = j-1<0?0:posCache[j-1];
 62                     if(scrollValue <= pos){
 63                         var len:Number = pos - lastPos;
 64                         var len1:Number = scrollValue - lastPos;
 65                         if(len1>len*99/100){
 66                             scrollLine = j;
 67                         }else{
 68                             scrollLine = j-1;
 69                         }
 70                         
 71                         break;
 72                     }
 73                 }
 74             }
 75             
 76             if (!cacheContent) {
 77                 var index:int = scrollLine * lineX;
 78                 var num:int = 0;
 79                 
 80                 if (index > _startIndex) {
 81                     num = index - _startIndex;
 82                     var down:Boolean = true;
 83                     var toIndex:int = _startIndex + lineX * (lineY + 1);
 84                     _isMoved = true;
 85                 } else if (index < _startIndex) {
 86                     num = _startIndex - index;
 87                     down = false;
 88                     toIndex = _startIndex - 1;
 89                     _isMoved = true;
 90                 }
 91                 
 92                 for (var i:int = 0; i < num; i++) {
 93                     if (down) {
 94                         var cell:Box = _cells.shift();
 95                         _cells[_cells.length] = cell;
 96                         var cellIndex:int = toIndex + i;
 97                     } else {
 98                         cell = _cells.pop();
 99                         _cells.unshift(cell);
100                         cellIndex = toIndex - i;
101                     }
102                     pos = Math.floor(cellIndex / lineX) * _cellSize;
103                     _isVertical ? cell.y = pos : cell.x = pos;
104                     renderItem(cell, cellIndex);
105                 }
106                 _startIndex = index;
107                 changeSelectStatus();
108             } else {
109                 num = (lineY + 1);
110                 if (_createdLine - scrollLine < num) {
111                     _createItems(_createdLine, lineX, _createdLine + num);
112                     renderItems(_createdLine * lineX, 0);
113                     _createdLine += num;
114                 }
115             }
116             
117             var r:Rectangle = _content.scrollRect;
118             if (_isVertical) {
119                 r.y = scrollValue - _offset.y;
120                 r.x = -_offset.x;
121             } else {
122                 r.y = -_offset.y;
123                 r.x = scrollValue - _offset.x;
124             }
125             _content.scrollRect = r;
126         }
127         
128         private function _createItems(startY:int, numX:int, numY:int):void {
129             var box:Box = _content;
130             var cell:Box = _getOneCell();
131             var cellWidth:Number = cell.width + _spaceX;
132             var cellHeight:Number = cell.height + _spaceY;
133             
134             if (cacheContent) {
135                 var cacheBox:Box = new Box();
136                 cacheBox.cacheAsBitmap = true;
137                 cacheBox.pos((_isVertical ? 0 : startY) * cellWidth, (_isVertical ? startY : 0) * cellHeight);
138                 _content.addChild(cacheBox);
139                 _content.optimizeScrollRect = true;
140                 box = cacheBox;
141             } else {
142                 var arr:Array = [];
143                 for (var i:int = _cells.length - 1; i > -1; i--) {
144                     var item:Box = _cells[i];
145                     item.removeSelf();
146                     arr.push(item);
147                 }
148                 _cells.length = 0;
149             }
150             
151             for (var k:int = startY; k < numY; k++) {
152                 for (var l:int = 0; l < numX; l++) {
153                     if (arr && arr.length) {
154                         cell = arr.pop();
155                     } else {
156                         cell = createItem();
157                     }
158                     cell.x = (_isVertical ? l : k) * cellWidth - box.x;
159                     cell.y = (_isVertical ? k : l) * cellHeight - box.y;
160                     cell.name = "item" + (k * numX + l);
161                     box.addChild(cell);
162                     addCell(cell);
163                 }
164             }
165         }
166         
167         private function _getOneCell():Box {
168             if (_cells.length === 0) {
169                 var item:Box = createItem();
170                 _offset.setTo(item.x, item.y);
171                 if (cacheContent) return item;
172                 _cells.push(item);
173             }
174             return _cells[0];
175         }
176         
177         private function posCell(cell:Box, cellIndex:int):void {
178             if (!_scrollBar) return;
179             var lineX:int = (_isVertical ? this.repeatX : this.repeatY);
180             var lineY:int = (_isVertical ? this.repeatY : this.repeatX);
181             var pos:Number = Math.floor(cellIndex / lineX) * _cellSize;
182             _isVertical ? cell.y = pos : cell.x = pos;
183             
184             //CList: 新增posHandler --ixenos 2020-10-27 15:00:17
185             posHandler && posHandler.runWith([_isVertical, cell, pos, cellIndex]);
186             posCache[cellIndex] = cell.y;
187         }
188         
189         private function _bindData(cell:*, data:Object):void {
190             var arr:Array = cell._$bindData;
191             for (var i:int = 0, n:int = arr.length; i < n; i++) {
192                 var ele:* = arr[i++];
193                 var prop:String = arr[i++];
194                 var value:String = arr[i];
195                 var fun:Function = UIUtils.getBindFun(value);
196                 ele[prop] = fun.call(this, data);
197             }
198         }
199         
200         /**
201          * @private
202          * 更改单元格的信息。
203          * @internal 在此销毁、创建单元格,并设置单元格的位置等属性。相当于此列表内容发送改变时调用此函数。
204          */
205         override protected function changeCells():void {
206             _cellChanged = false;
207             if (_itemRender) {
208                 //获取滚动条
209                 scrollBar = getChildByName("scrollBar") as ScrollBar;
210                 
211                 //自适应宽高                
212                 var cell:Box = _getOneCell();
213                 
214                 var cellWidth:Number = (cell.width + _spaceX) || 1;
215                 var cellHeight:Number = (cell.height + _spaceY) || 1;
216                 if (_width > 0) _repeatX2 = _isVertical ? Math.round(_width / cellWidth) : Math.ceil(_width / cellWidth);
217                 if (_height > 0) _repeatY2 = _isVertical ? Math.ceil(_height / cellHeight) : Math.round(_height / cellHeight);
218                 
219                 var listWidth:Number = _width ? _width : (cellWidth * repeatX - _spaceX);
220                 var listHeight:Number = _height ? _height : (cellHeight * repeatY - _spaceY);
221                 _cellSize = _isVertical ? cellHeight : cellWidth;
222                 _cellOffset = _isVertical ? (cellHeight * Math.max(_repeatY2, _repeatY) - listHeight - _spaceY) : (cellWidth * Math.max(_repeatX2, _repeatX) - listWidth - _spaceX);
223                 
224                 if (_isVertical && _scrollBar) _scrollBar.height = listHeight;
225                 else if (!_isVertical && _scrollBar) _scrollBar.width = listWidth;
226                 setContentSize(listWidth, listHeight);
227                 
228                 //创建新单元格                
229                 var numX:int = _isVertical ? repeatX : repeatY;
230                 var numY:int = (_isVertical ? repeatY : repeatX) + (_scrollBar ? 1 : 0);
231                 _createItems(0, numX, numY);
232                 _createdLine = numY;
233                 
234                 if (_array) {
235                     array = _array;
236                     runCallLater(renderItems);
237                 }
238             }
239         }
240     }

2.业务伪代码

 1         private function init():void
 2         {
 3             lui.listCate.posHandler = Handler.create(this, listCatePos, null, false);
 4             lui.listCate.repeatY = 4;
 5             lui.listCate.scrollBar.max = getListContentHeight();
 6         }
 7 
 8         private function onToggleCate(index:int):void{
 9             var dat:* = lui.listCate.getItem(index);
10             dat["open"] = !dat["open"];
11             lui.listCate.setItem(index, dat);
12             lui.listCate.refresh();
13             lui.listCate.scrollBar.max = getListContentHeight();
14         }
15         
16         private function getOpenNumBeforeCurIdx(curIdx:int):int{
17             var ret:int = 0;
18             for (var i:int = 0; i < curIdx; i++) {
19                 var dat:* = lui.listCate.getItem(i);
20                 if(dat && dat["open"]){
21                     ret++;
22                 }
23             }
24             return ret;
25         }
26         
27         private function getListContentHeight():Number{
28             var ret:Number = 130 * lui.listCate.length + lui.listCate.spaceY * (lui.listCate.length - 1) - 440;//TODO 这个值需要参数绑定
29             for (var i:int = 0; i < lui.listCate.length; i++) {
30                 var dat:* = lui.listCate.getItem(i);
31                 ret += dat["open"]?_subH:0;
32             }
33             ret -= lui.listCate.spaceY;
34             return ret;
35         }
36         
37         private function listCatePos(isVertical:Boolean,cell:Box, pos:Number, index:int):Number{
38             var totalOpenNum:int = getOpenNumBeforeCurIdx(index);
39             var closeLength:Number = (index - totalOpenNum) * _subH;
40             pos -= closeLength;
41             if(isVertical){
42                 cell.y = pos;
43             }else{
44                 cell.x = pos;
45             }
46             
47             return pos;
48         }
49         
50         private function listCateRender(cell:StageSelectItem, index:int):void{
51             var dat:* = lui.listCate.getItem(index);
52             var isOpen:Boolean = dat["open"];
53             var totalOpenNum:int = getOpenNumBeforeCurIdx(index);
54             cell.updateView(index, isOpen, totalOpenNum);
55             cell.toggleHandler = Handler.create(this, onToggleCate, [index], false);
56         }
 
原文地址:https://www.cnblogs.com/ixenos/p/13895816.html