Laya 实现带有子菜单的List
Laya 用List实现固定大小的二级菜单
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 }