protected override bool AdjustmentItemSize(ScrollListItem item) { if (item.width != itemDefaultfSize.x || item.height != itemDefaultfSize.y) { item.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, itemDefaultfSize.x); item.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, itemDefaultfSize.y); } return(false); }
protected override bool AdjustmentItemSize(ScrollListItem item) { if (item.height != _itemModels[item.index].height) { //Debug.Log($"item[{item.index}]的尺寸改变 {_itemModels[item.index].height} => {item.height}"); _itemModels[item.index].height = item.height; return(true); } return(false); }
protected override bool AdjustmentItemSize(ScrollListItem item) { if (item.width != _itemModels[item.index].width) { //Debug.Log($"item[{item.index}]的尺寸改变 {_itemModels[item.index].width} => {item.width}"); _itemModels[item.index].width = item.width; return(true); } return(false); }
protected override void Refresh(UpdateData updateConfig, out int lastStartIndex) { if (updateConfig.keepPaddingType == EKeepPaddingType.END) { var targetRenderStartPos = (ContentHeight - updateConfig.tempLastContentRect.height) + contentRenderStartPos; var temp = content.localPosition; temp.y = targetRenderStartPos; content.localPosition = temp; } contentRenderStartPos = content.localPosition.y; if (contentRenderStartPos < 0) { contentRenderStartPos = 0; } else if (contentRenderStartPos > ContentHeight - viewportSize.y) { contentRenderStartPos = ContentHeight - viewportSize.y; } int dataIdx; float startPos = layout.paddingTop; for (dataIdx = 0; dataIdx < _itemModels.Count; dataIdx++) { var dataBottom = startPos + _itemModels[dataIdx].height; if (dataBottom >= contentRenderStartPos) { //就是我了 break; } startPos = dataBottom + layout.gap; } lastStartIndex = dataIdx; //显示的内容刚好大于这个值即可 float contentHeightLimit = viewportSize.y; float itemY = -startPos; /// <summary> /// 最后一次显示的Item的缓存 /// </summary> Dictionary <ScrollListItemModel, ScrollListItem> lastShowingItems = new Dictionary <ScrollListItemModel, ScrollListItem>(_showingItems); _showingItems.Clear(); while (dataIdx < _itemModels.Count) { var model = _itemModels[dataIdx]; ScrollListItem item = CreateItem(model, dataIdx, lastShowingItems); //item.gameObject.name += $"_{_itemModels[dataIdx].height}"; _showingItems[model] = item; var pos = Vector3.zero; pos.y = itemY; item.rectTransform.localPosition = pos; //下一个item的Y坐标 itemY -= (item.height + layout.gap); //下一个item的索引 dataIdx++; if (-contentRenderStartPos - itemY >= contentHeightLimit) { break; } } //回收没有使用的item RecycleUselessItems(lastShowingItems); }
/// <summary> /// 创建一个列表项Item /// </summary> /// <param name="data"></param> /// <param name="dataIdx"></param> /// <param name="lastShowingItems"></param> /// <returns></returns> protected ScrollListItem CreateItem(ScrollListItemModel model, int dataIdx, Dictionary <ScrollListItemModel, ScrollListItem> lastShowingItems) { ScrollListItem item; if (lastShowingItems.ContainsKey(model) && lastShowingItems[model].index == dataIdx) //本来就在显示列表中,直接返回 { item = lastShowingItems[model]; lastShowingItems.Remove(model); } else { if (_recycledItems.Count > 0) { ScrollListItem tempItem = null; //tempItem = _recycledItems[0]; int idx = _recycledItems.Count; while (--idx > -1) { tempItem = _recycledItems[idx]; if (tempItem.index == dataIdx && tempItem.data.Equals(model.data)) //以前回收的一个对象,刚好对应的数据一致,直接返回 { item = tempItem; _recycledItems.RemoveAt(idx); item.gameObject.SetActive(true); RenderItem(item, model.data, false); return(item); } } //没有绝对匹配的,则抽取最后找到的item,之后刷新数据并返回 item = tempItem; _recycledItems.Remove(tempItem); //当一个列表项,将被复用时触发 onItemBeforeReuse?.Invoke(item); } else { var go = GameObject.Instantiate(itemPrefab, content); if (false == go.activeInHierarchy) { go.SetActive(true); } item = go.AddComponent <ScrollListItem>(); item.rectTransform.anchorMin = Vector2.up; item.rectTransform.anchorMax = Vector2.up; item.rectTransform.pivot = Vector2.up; //Debug.Log($"新生成的 Item GameObject"); } var name = string.Format("item_{0}", dataIdx); item.gameObject.name = name; item.index = dataIdx; item.data = model.data; item.width = _itemModels[dataIdx].width; item.height = _itemModels[dataIdx].height; if (false == item.gameObject.activeInHierarchy) { item.gameObject.SetActive(true); } RenderItem(item, model.data, true); } if (item.index != dataIdx) { //插入列表项可能导致数据索引改变 item.index = dataIdx; } return(item); }
/// <summary> /// 检测并校正item的大小,如果进行了校正,返回true /// </summary> /// <param name="item"></param> /// <returns></returns> protected abstract bool AdjustmentItemSize(ScrollListItem item);
protected void RenderItem(ScrollListItem item, object data, bool isOnlySwitchActive) { onRenderItem?.Invoke(item, data, isOnlySwitchActive); }
protected override void Refresh(UpdateData updateConfig, out int lastStartIndex) { //内容容器宽度 var contentWidth = content.rect.width; if (updateConfig.keepPaddingType == EKeepPaddingType.END) { var targetRenderStartPos = (contentWidth - updateConfig.tempLastContentRect.width) + contentRenderStartPos; var temp = content.localPosition; temp.x = -targetRenderStartPos; content.localPosition = temp; } //content的滚动是负数 contentRenderStartPos = -content.localPosition.x; if (contentRenderStartPos < 0) { contentRenderStartPos = 0; } else if (contentRenderStartPos > contentWidth - viewportSize.x) { contentRenderStartPos = contentWidth - viewportSize.x; } int dataIdx; float startPos = layout.paddingLeft; for (dataIdx = 0; dataIdx < _itemModels.Count; dataIdx++) { var dataRight = startPos + _itemModels[dataIdx].width; if (dataRight >= contentRenderStartPos) { //就是我了 break; } startPos = dataRight + layout.gap; } lastStartIndex = dataIdx; //显示的内容刚好大于这个值即可 float contentWidthLimit = viewportSize.x; float itemX = startPos; /// <summary> /// 最后一次显示的Item的缓存 /// </summary> Dictionary <ScrollListItemModel, ScrollListItem> lastShowingItems = new Dictionary <ScrollListItemModel, ScrollListItem>(_showingItems); _showingItems.Clear(); while (dataIdx < _itemModels.Count) { var model = _itemModels[dataIdx]; ScrollListItem item = CreateItem(model, dataIdx, lastShowingItems); //item.gameObject.name += $"_{_itemModels[dataIdx].height}"; _showingItems[model] = item; var pos = Vector3.zero; pos.x = itemX; item.rectTransform.localPosition = pos; //下一个item的X坐标 itemX += (item.width + layout.gap); //下一个item的索引 dataIdx++; if (itemX - contentRenderStartPos >= contentWidthLimit) { break; } } //回收没有使用的item RecycleUselessItems(lastShowingItems); }
protected override void Refresh(UpdateData updateConfig, out int lastStartIndex) { var scrollX = -content.localPosition.x; if (scrollX < 0) { scrollX = 0; } var scrollY = content.localPosition.y; if (scrollY < 0) { scrollY = 0; } bool isColByCol = layout.constraint == EGridConstraint.FIXED_ROW_COUNT ? true : false; //计算出关联的所有Item的索引 List <GridPos> list = new List <GridPos>(); lastStartIndex = 0; if (colCount > 0 && rowCount > 0) { //根据滚动区域左上角算出起始item的二维位置; GridPos startPos = new GridPos((int)(scrollX / _bigW), (int)(scrollY / _bigH), colCount, rowCount, _bigW, _bigH); lastStartIndex = startPos.index; //根据滚动区域左下角算出结束item的二维位置 GridPos endPos = new GridPos((int)((scrollX + viewportSize.x) / _bigW), (int)((scrollY + viewportSize.y) / _bigH), colCount, rowCount, _bigW, _bigH); if (isColByCol) { RefreshGridPosColByCol(list, ref startPos, ref endPos); } else { RefreshGridPosRowByRow(list, ref startPos, ref endPos); } } /// <summary> /// 最后一次显示的Item的缓存 /// </summary> Dictionary <ScrollListItemModel, ScrollListItem> lastShowingItems = new Dictionary <ScrollListItemModel, ScrollListItem>(_showingItems); _showingItems.Clear(); for (int i = 0; i < list.Count; i++) { var gridPos = list[i]; var model = _itemModels[gridPos.index]; ScrollListItem item = CreateItem(model, gridPos.index, lastShowingItems); _showingItems[model] = item; var pos = new Vector3(gridPos.pixelX, -gridPos.pixelY, 0); pos.x += layout.paddingLeft; pos.y -= layout.paddingTop; item.rectTransform.localPosition = pos; } //回收没有使用的item RecycleUselessItems(lastShowingItems); }