Unity中实现带缓冲池的Listview(buffer listview)
来源:互联网 发布:java读取压缩包 编辑:程序博客网 时间:2024/06/16 17:12
- 实测实现了一个10000条数据的Listview,sony z3真机瞬间完成初始化,滑动无比流畅。
下面的截图是实际项目中使用的效果,实例化三个cellPrefab作为缓冲池,改变它们的位置和数据填充来模拟一个数据长度为15的listview:
下面直接给出完整代码,函数命名简明,希望大家能看明白:
using UnityEngine;using UnityEngine.UI;using System.Collections;using UnityEngine.EventSystems;using System;using System.Collections.Generic;using Framework;using DG.Tweening;//create by YJXpublic class AListView : LayoutGroup{ private float visualDIA; private int eachBufferCount; private ScrollRect scrollRect; private RectTransform scrollRectTransform; [HideInInspector] private Vector2[] cellSizes; private List<IndexAndBuffer>[] buffersArray; private List<IndexAndPos> cellsPosInfo = new List<IndexAndPos>(); private List<int> showingCells = new List<int>();//index public Action OnDataFillCompleted; [SerializeField] private ListViewAdapter _adapter; private float width; private float height; public GameObject[] prefabs; public string mainCellname; private float[] fixedHeightArray; private int CellsCount { get { return this.Adapter.GetCount(); } } public bool isManualFill = false; public float bufferFactor = 1f; public ListViewAdapter Adapter { get { return _adapter; } set { _adapter = value; if (isManualFill && this.gameObject.activeInHierarchy == true && Application.isPlaying) { _adapter.aListview = this; if (isManualFill) { Adapter.Initialize(); Initialize(); } } } } // Use this for initialization protected override void Start() { if (this.Adapter != null && !isManualFill && Application.isPlaying) { Adapter.Initialize(); Initialize(); } } public void Initialize(Action onComplete = null) { if (mainCellname != string.Empty) { string[] difCell = mainCellname.Split(','); for (int i = 0; i < difCell.Length; i++) { prefabs[i] = Resources.Load<GameObject>(difCell[i]); } } this.scrollRectTransform = transform.parent.GetComponent<RectTransform>(); this.scrollRect = this.scrollRectTransform.GetComponent<ScrollRect>(); this.fixedHeightArray = new float[this.CellsCount]; this.width = this.scrollRectTransform.sizeDelta.x; this.height = this.scrollRectTransform.sizeDelta.y; this.cellSizes = new Vector2[this.prefabs.Length]; for (int i = 0; i < this.prefabs.Length; i++) { RectTransform cellRect = this.prefabs[i].GetComponent<RectTransform>(); this.cellSizes[i] = cellRect.sizeDelta; } if (this.scrollRect.horizontal) { this.visualDIA = (0.5f + this.bufferFactor) * this.width; } else if (this.scrollRect.vertical) { this.visualDIA = (0.5f + this.bufferFactor) * this.height; } this.eachBufferCount = this.GetEachBufferCount(); //StartCoroutine(GenerateCellBuffers()); GenerateCellBuffers(); CalculateSizeAndCellPos(); this.scrollRect.onValueChanged.AddListener(FillData); FillData(Vector2.zero); if (OnDataFillCompleted != null) { OnDataFillCompleted(); } } public void ReFillData() { ForceRecycleAllBuffers(); CalculateSizeAndCellPos(); FillData(Vector2.zero); if (OnDataFillCompleted != null) { OnDataFillCompleted(); } } public void RefreshData() { ForceRecycleAllBuffers(); CalculateSizeAndCellPos(false); FillData(Vector2.zero); } private int GetEachBufferCount() { //float scrollDistance = 0f; float totalEachCellDistance = 0f; if (this.scrollRect.horizontal) { for (int i = 0; i < this.cellSizes.Length; i++) { totalEachCellDistance += this.cellSizes[i].x; } } else if (this.scrollRect.vertical) { for (int i = 0; i < this.cellSizes.Length; i++) { totalEachCellDistance += this.cellSizes[i].y; } } int eachBuffCount = Mathf.CeilToInt((this.visualDIA * 2f) / totalEachCellDistance); return eachBuffCount; } private void GenerateCellBuffers() { this.buffersArray = new List<IndexAndBuffer>[this.prefabs.Length]; for (int i = 0; i < this.prefabs.Length; i++) { this.buffersArray[i] = new List<IndexAndBuffer>(); } /* 根据bufferFactor,协程预先生成相应个数的buffer int showingCount = Mathf.CeilToInt(this.eachBufferCount / ((0.5f + this.bufferFactor))); showingCount = showingCount >= this.eachBufferCount ? this.eachBufferCount - 1 : showingCount; for (int i = 0; i < this.eachBufferCount; i++) { for (int j = 0; j < this.prefabs.Length; j++) { GameObject go = GameObject.Instantiate<GameObject>(this.prefabs[j]) as GameObject; RectTransform rect = go.GetComponent<RectTransform>(); rect.SetParent(transform); rect.localScale = Vector3.one; go.SetActive(false); this.buffersArray[j].Add(new IndexAndBuffer(-1, go, false)); } //if (i >= showingCount) //{ // this.scrollRect.onValueChanged.Invoke(Vector2.zero); //} //yield return null; } this.scrollRect.onValueChanged.Invoke(Vector2.zero); yield return null; * */ } public float CalculateSizeAndCellPos(bool isGotoBegin = true) { this.cellsPosInfo.Clear(); float length = 0; float offset = 0; if (this.scrollRect.vertical) { for (int i = 0; i < this.CellsCount; i++) { int prefabIndex = this.Adapter.GetCellPrefabIndex(i); length += this.cellSizes[prefabIndex].y; } RectTransform rt = this.transform.parent.GetComponent<RectTransform>(); if (length < rt.sizeDelta.y) { length = rt.sizeDelta.y; } this.rectTransform.sizeDelta = new Vector2(this.rectTransform.sizeDelta.x, length); if (isGotoBegin == true) { this.transform.localPosition = new Vector3(0.0f, -(length / 2.0f - rt.sizeDelta.y / 2.0f), 0.0f); } for (int i = 0; i < this.CellsCount; i++) { int prefabIndex = this.Adapter.GetCellPrefabIndex(i); float cellHeight = this.cellSizes[prefabIndex].y; Vector3 localPos = new Vector3(0.0f, (length / 2.0f - offset - cellHeight / 2.0f), 0.0f); this.cellsPosInfo.Add(new IndexAndPos(i, localPos)); offset += cellHeight; } } else if (this.scrollRect.horizontal) { for (int i = 0; i < this.CellsCount; i++) { int prefabIndex = this.Adapter.GetCellPrefabIndex(i); length += this.cellSizes[prefabIndex].x; } RectTransform rt = this.transform.parent.GetComponent<RectTransform>(); if (length < rt.sizeDelta.x) { length = rt.sizeDelta.x; } this.rectTransform.sizeDelta = new Vector2(length, this.rectTransform.sizeDelta.y); if (isGotoBegin == true) { this.transform.localPosition = new Vector3(-(length / 2.0f - rt.sizeDelta.y / 2.0f), 0.0f, 0.0f); } for (int i = 0; i < this.CellsCount; i++) { int prefabIndex = this.Adapter.GetCellPrefabIndex(i); float cellWidth = this.cellSizes[prefabIndex].x; Vector3 localPos = new Vector3((length / 2.0f - offset - cellWidth / 2.0f), 0.0f, 0.0f); this.cellsPosInfo.Add(new IndexAndPos(i, localPos)); offset += cellWidth; } } return length; } private void FillData(Vector2 vec2) { RecycleBuffers(); if (this.scrollRect.horizontal) { float currentPos = -this.rectTransform.localPosition.x; for (int i = 0; i < this.cellsPosInfo.Count; i++) { IndexAndPos indexAndPos = cellsPosInfo[i]; float distance2Mid = Mathf.Abs(indexAndPos.localPos.x - currentPos); if (distance2Mid <= this.visualDIA /** this.width*/ && !this.showingCells.Contains(indexAndPos.mainIndex)) { IndexAndBuffer buffer = GetUsableBuffer(indexAndPos.mainIndex); if (buffer != null) { buffer.isUsing = true; buffer.mainIndex = indexAndPos.mainIndex; buffer.bufferGo.SetActive(true); buffer.bufferGo.transform.localPosition = indexAndPos.localPos; buffer.bufferGo.name = indexAndPos.mainIndex.ToString(); this.Adapter.FillItemData(buffer.bufferGo, indexAndPos.mainIndex); } } } } else if (this.scrollRect.vertical) { float currentPos = -this.rectTransform.localPosition.y; for (int i = 0; i < this.cellsPosInfo.Count; i++) { IndexAndPos indexAndPos = cellsPosInfo[i]; float distance2Mid = Mathf.Abs(indexAndPos.localPos.y - currentPos); if (distance2Mid <= this.visualDIA /** this.width*/ && !this.showingCells.Contains(indexAndPos.mainIndex)) { IndexAndBuffer buffer = GetUsableBuffer(indexAndPos.mainIndex); if (buffer != null) { buffer.isUsing = true; buffer.mainIndex = indexAndPos.mainIndex; buffer.bufferGo.SetActive(true); buffer.bufferGo.transform.localPosition = indexAndPos.localPos; buffer.bufferGo.name = indexAndPos.mainIndex.ToString(); this.Adapter.FillItemData(buffer.bufferGo, indexAndPos.mainIndex); } } } } } private IndexAndBuffer GetUsableBuffer(int index) { int prefabIndex = this.Adapter.GetCellPrefabIndex(index); List<IndexAndBuffer> buffers = this.buffersArray[prefabIndex]; for (int i = 0; i < buffers.Count; i++) { if (!buffers[i].isUsing) { this.showingCells.Add(index); return buffers[i]; } } GameObject go = GameObject.Instantiate<GameObject>(this.prefabs[prefabIndex]) as GameObject; RectTransform rect = go.GetComponent<RectTransform>(); rect.SetParent(transform); rect.localScale = Vector3.one; go.SetActive(false); IndexAndBuffer buffer = new IndexAndBuffer(-1, go, false); this.buffersArray[prefabIndex].Add(buffer); this.showingCells.Add(index); return buffer; } private void ForceRecycleAllBuffers() { for (int i = 0; i < this.buffersArray.Length; i++) { List<IndexAndBuffer> buffers = this.buffersArray[i]; for (int j = 0; j < buffers.Count; j++) { IndexAndBuffer buffer = buffers[j]; buffer.isUsing = false; buffer.bufferGo.SetActive(false); this.showingCells.Remove(buffer.mainIndex); } } } private void RecycleBuffers() { if (this.scrollRect.horizontal) { float currentPos = -this.rectTransform.localPosition.x; for (int i = 0; i < this.buffersArray.Length; i++) { List<IndexAndBuffer> buffers = this.buffersArray[i]; for (int j = 0; j < buffers.Count; j++) { IndexAndBuffer buffer = buffers[j]; float distance2Mid = Mathf.Abs(buffer.bufferGo.transform.localPosition.x - currentPos); if (buffer.isUsing && distance2Mid > this.visualDIA) { buffer.isUsing = false; buffer.bufferGo.SetActive(false); this.showingCells.Remove(buffer.mainIndex); } } } } else if (this.scrollRect.vertical) { float currentPos = -this.rectTransform.localPosition.y; for (int i = 0; i < this.buffersArray.Length; i++) { List<IndexAndBuffer> buffers = this.buffersArray[i]; for (int j = 0; j < buffers.Count; j++) { IndexAndBuffer buffer = buffers[j]; float distance2Mid = Mathf.Abs(buffer.bufferGo.transform.localPosition.y - currentPos); if (buffer.isUsing && distance2Mid > this.visualDIA) { buffer.isUsing = false; buffer.bufferGo.SetActive(false); this.showingCells.Remove(buffer.mainIndex); } } } } }public void GotoIndex(int index, float duration = 0.5f) { if (index > this.CellsCount) { ADebug.LogError("越界 越界 越界 越界 越界 越界 越界 越界 越界 越界 "); return; } if (this.scrollRect.vertical) { float height = 0; for (int i = 0; i < index; i++) { int prefabIndex = this.Adapter.GetCellPrefabIndex(i); height += this.cellSizes[prefabIndex].y; } RectTransform rt = this.transform.parent.GetComponent<RectTransform>(); if (height < rt.sizeDelta.y) { height = rt.sizeDelta.y; } height = (this.rectTransform.sizeDelta.y - rt.sizeDelta.y) / 2 - height; this.transform.DOLocalMoveY(-height, duration); } else if (this.scrollRect.horizontal) { float width = 0; for (int i = 0; i < index; i++) { int prefabIndex = this.Adapter.GetCellPrefabIndex(i); width += this.cellSizes[prefabIndex].x; } RectTransform rt = this.transform.parent.GetComponent<RectTransform>(); if (width < rt.sizeDelta.x) { width = rt.sizeDelta.x; } width = (this.rectTransform.sizeDelta.x - rt.sizeDelta.x) / 2 - width;// -base.spacing.y * (index - 1); this.transform.DOLocalMoveX(-width, duration); CalculateLayoutInputHorizontal(); } } #region override public override void CalculateLayoutInputVertical() { //Debug.Log("CalculateLayoutInputVertical"); } public override void SetLayoutHorizontal() { //Debug.Log("SetLayoutHorizontal"); } public override void SetLayoutVertical() { //Debug.Log("SetLayoutVertical"); } #endregion}public class IndexAndPos //for each cell{ public int mainIndex; public Vector3 localPos; public Vector2 cellSize; public IndexAndPos(int index, Vector3 localPos) { this.mainIndex = index; this.localPos = localPos; }}public class IndexAndBuffer{ public int mainIndex; public GameObject bufferGo; public bool isUsing; public IndexAndBuffer(int index, GameObject buffer, bool isUsing) { this.mainIndex = index; this.bufferGo = buffer; this.isUsing = isUsing; }}
- 数据填充器:
public abstract class ListViewAdapter : MonoBehaviour { [HideInInspector] public AListView aListview; public virtual void Initialize() { } public abstract int GetCount(); public abstract void FillItemData(GameObject item, int cellindex); public virtual int GetCellPrefabIndex(int index) { return 0; }}
阅读全文
1 0
- Unity中实现带缓冲池的Listview(buffer listview)
- 实现带图标的ListView
- 实现带标题的ListView
- 实现带图标的ListView
- android中实现带图片和checkbox的listview
- 自定义带图片的ListView的实现
- Android: 带图标的ListView实现
- 实现带图片和checkbox的listview
- Android---自定义带CheckBox的ListView实现
- 实现带图片和checkbox的listview
- Android实现带图标的ListView
- Android实现带图标的ListView
- 实例2:实现带图标的ListView
- ListView中使用带Edittext的item
- 带checkBox的ListView
- 带CheckBox的ListView
- 带CheckBox的ListView
- 带图的listview
- 大数据:Spark mlib(二) Naive bayes朴素贝叶斯分类之多元朴素贝叶斯源码分析
- altera小实验——TimeQuest Timing Analyzer初步使用
- MD5加密工具类
- c 使用RTP协议发送视频数据
- MongoDB
- Unity中实现带缓冲池的Listview(buffer listview)
- 三种循环的流程图画法总结 (转载)
- 使用iframe来实现的系统,长时间未操作易发生的尴尬界面
- AES加密的四种模式详解
- 决策树算法学习笔记(一)
- 10个令人相见恨晚的R语言包
- BZOJ 1030 [JSOI2007]文本生成器 DP+AC自动机
- shell编写的一个小误区
- mybatis-2