using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; using DG.Tweening; /// /// 滑动列表的优化,用少量元素显示很多物体. 修改自UIWarpConten 和gLoop --ljp20170328 /// public class ViewList : MonoBehaviour { /// /// 元素初始化 /// /// 游戏对象 /// 对象在prefab中的序号 /// 对象在数组中的序号 public delegate void OnInitializeItem(GameObject item, int wrapIndex, int realIndex); /// /// 元素初始化 /// public OnInitializeItem onInitializeItem; /// /// 排列 /// public enum Arrangement { /// /// 横 /// Horizontal, /// /// 竖 /// Vertical, } /// /// 排列方式 /// public Arrangement arrangeType = Arrangement.Horizontal; /// /// The width of each of the cells. /// public float cellWidth = 200f; /// /// The height of each of the cells. /// public float cellHeight = 200f; /// /// 窗口能容纳的 行数 或 列数 /// public int viewCount = 5; /// /// 对象最小序号 /// public int minIndex = 0; /// /// 对象最大序号 /// public int maxIndex = 0; /// ///当前对象 /// Transform mTrans; /// /// 当前RectTransform对象 /// RectTransform mRTrans; /// /// ScrollRect /// ScrollRect mScroll; /// /// 元素预制物体的容器对象 /// public Transform content = null; /// /// 元素预制物体 /// public GameObject goItemPrefab = null; /// /// 最少需要多少预制物体 /// public int mMinNum = 0; /// /// 滚动方向 /// bool mHorizontal; /// /// 元素链表 /// List mChild = new List(); /// /// 显示区域长度或高度的一半 /// float extents = 0; Vector2 SR_size = Vector2.zero;//SrollRect的尺寸 Vector3[] conners = new Vector3[4];//ScrollRect四角的世界坐标 Vector2 startPos;//ScrollRect的初始位置 /// /// 是否隐藏裁剪部分 /// public bool cullContent = true; /// /// 将已有的对象初始化一下. /// public void SetData() { for (int i = 0; i < mChild.Count; i++) { Transform temp = mChild[i]; UpdateItem(temp, i, i); } } /// /// 加载动画 /// /// /// /// private void Dotween(Transform temp, Vector3 destPos, int i) { Tweener tweener = null; RectTransform panelTransform = temp.GetComponent(); temp.localPosition = new Vector3(destPos.x, -cellHeight * 5, 0); tweener = panelTransform.DOLocalMove(destPos, 0.3f); tweener.SetEase(Ease.Linear);//动画曲线 tweener.SetDelay(i * 0.01f); } /// /// 实例化预设对象 、添加实例化对象到指定的子对象下 /// /// 元素预制物体 /// 父节点 /// 新创建的元素对象 private GameObject addChild(GameObject goPrefab, Transform parent) { if (goPrefab == null || parent == null) { LogHelper.LogError("异常。UIWarpContent addChild(goPrefab = null || parent = null)"); return null; } GameObject goChild = GameObject.Instantiate(goPrefab) as GameObject; goChild.transform.SetParent(parent, false); goChild.SetActive(true); return goChild; } public void Init() { for (int i = 0; i < mMinNum; i++) { addChild(goItemPrefab, content); } } /// /// 开始函数,将动画放到这里,每当第一次运行会显示动画. /// void Start() { InitList(); } /// /// 初始化mChild链表 /// void InitList() { int i, ChildCount; InitValue(); mChild.Clear(); for (i = 0, ChildCount = mTrans.childCount; i < ChildCount; i++) mChild.Add(mTrans.GetChild(i)); ////动画放到下面这个函数里 ResetChildPosition(); // LogHelper.Log(mTrans.localPosition.y + " " + startPos.y + " " + cellHeight); if (mTrans.localPosition.y > 2 * cellHeight && mTrans.localPosition.y<6 *cellHeight) { mTrans.localPosition = new Vector3(startPos.x, startPos.y - 3*cellHeight, 0); } } void InitValue() { if (viewCount <= 0) viewCount = 1; if (minIndex > maxIndex) minIndex = maxIndex; mTrans = transform; mRTrans = transform.GetComponent(); mScroll = transform.parent.GetComponent(); mHorizontal = mScroll.horizontal; SR_size = transform.parent.GetComponent().rect.size; //四角坐标 横着数 conners[0] = new Vector3(-SR_size.x / 2f, SR_size.y / 2f, 0); conners[1] = new Vector3(SR_size.x / 2f, SR_size.y / 2f, 0); conners[2] = new Vector3(-SR_size.x / 2f, -SR_size.y / 2f, 0); conners[3] = new Vector3(SR_size.x / 2f, -SR_size.y / 2f, 0); for (int i = 0; i < 4; i++) { Vector3 temp = transform.parent.TransformPoint(conners[i]); conners[i].x = temp.x; conners[i].y = temp.y; } mRTrans.pivot = new Vector2(0, 1);//设置panel的中心在左上角 mScroll.onValueChanged.AddListener(delegate { WrapContent(); });//添加滚动事件回调 startPos = mTrans.localPosition; } //初始化各Item的坐标 [ContextMenu("RePosition")] public virtual void RePosition() { InitList(); } void Update() { if (Application.isPlaying) enabled = false; RePosition(); } void ResetChildPosition() { int rows = 1, cols = 1; Vector2 startAxis = new Vector2(cellWidth / 10f, -cellHeight / 10f);//起始位置 int i; int imax = mChild.Count;//Item元素数量 //初始化行列数 if (arrangeType == Arrangement.Vertical) //垂直排列 则适应行数 { rows = viewCount; cols = (int)Mathf.Ceil((float)imax / (float)rows); extents = (float)(cols * cellWidth) * 0.5f; } else if (arrangeType == Arrangement.Horizontal) //水平排列则适应列数 { cols = viewCount; rows = (int)Mathf.Ceil((float)imax / (float)cols); extents = (float)(rows * cellHeight) * 0.5f; } for (i = 0; i < imax; i++) { Transform temp = mChild[i]; int x = 0, y = 0;//行列号 if (arrangeType == Arrangement.Horizontal) { x = i / cols; y = i % cols; } else if (arrangeType == Arrangement.Vertical) { x = i % rows; y = i / rows; } Vector3 destPos = new Vector3(startAxis.x + y * cellWidth, startAxis.y - x * cellHeight, 0); ////动画显示,缓动到目的位置; //if (arrangeType == Arrangement.Vertical) //{ // if (mRTrans.sizeDelta != new Vector2(destPos.x + cellWidth, viewCount * cellHeight)) // { // Dotween(temp, destPos, i); // } // else // { // temp.localPosition = destPos; // } //} //else //{ // if (mRTrans.sizeDelta != new Vector2(viewCount * cellWidth, -destPos.y + cellHeight)) // { // Dotween(temp, destPos, i); // } // else // { // temp.localPosition = destPos; // } //} temp.localPosition = destPos; // if (minIndex == maxIndex || (i >= minIndex && i <= maxIndex)) { cullContent = true; temp.gameObject.SetActive(true); UpdateRectsize(temp.localPosition);//更新panel的尺寸 mTrans.localPosition = startPos; UpdateItem(temp, i, i); // Dotween(temp, destPos, i); } else cullContent = temp.gameObject.activeInHierarchy;//如果预制Item数超过maxIndex则将超过部分隐藏 并 设置cullCintent为ufalse 并且不再更新 panel尺寸 } } /// /// 更新panel的尺寸 /// /// void UpdateRectsize(Vector2 pos) { if (arrangeType == Arrangement.Vertical) { mRTrans.sizeDelta = new Vector2(pos.x + cellWidth, viewCount * cellHeight); } else { mRTrans.sizeDelta = new Vector2(viewCount * cellWidth, -pos.y + cellHeight); } } int getRealIndex(Vector2 pos)//计算realindex { int x = (int)Mathf.Ceil(-pos.y / cellHeight) - 1;//行号 int y = (int)Mathf.Ceil(pos.x / cellWidth) - 1;//列号 int realIndex; if (arrangeType == Arrangement.Horizontal) realIndex = x * viewCount + y; else realIndex = x + viewCount * y; return realIndex; } void WrapContent() { // LogHelper.Log("ffdds"); Vector3[] conner_local = new Vector3[4]; for (int i = 0; i < 4; i++) { conner_local[i] = mTrans.InverseTransformPoint(conners[i]); } //计算ScrollRect的中心坐标 相对于this的坐标 Vector2 center = (conner_local[3] + conner_local[0]) / 2f; if (mHorizontal) { float min = conner_local[0].x - cellWidth;//显示区域 float max = conner_local[3].x + cellWidth; for (int i = 0, imax = mChild.Count; i < imax; i++) { Transform temp = mChild[i]; float distance = temp.localPosition.x - center.x; if (distance < -extents) { Vector2 pos = temp.localPosition; pos.x += extents * 2f; int realIndex = getRealIndex(pos); if (minIndex == maxIndex || (realIndex >= minIndex && realIndex < maxIndex)) { UpdateRectsize(pos); temp.localPosition = pos; //设置Item内容 UpdateItem(temp, i, realIndex); } } if (distance > extents) { Vector2 pos = temp.localPosition; pos.x -= extents * 2f; int realIndex = getRealIndex(pos); if (minIndex == maxIndex || (realIndex >= minIndex && realIndex < maxIndex)) { temp.localPosition = pos; //设置Item内容 UpdateItem(temp, i, realIndex); } } if (cullContent)//设置裁剪部分是否隐藏 { Vector2 pos = temp.localPosition; temp.gameObject.SetActive((pos.x > min && pos.x < max) ? true : false); } } } else { float min = conner_local[3].y - cellHeight;//显示区域 float max = conner_local[0].y + cellHeight; for (int i = 0, imax = mChild.Count; i < imax; i++) { Transform temp = mChild[i]; float distance = temp.localPosition.y - center.y; if (distance < -extents) { Vector2 pos = temp.localPosition; pos.y += extents * 2f; int realIndex = getRealIndex(pos); if (minIndex == maxIndex || (realIndex >= minIndex && realIndex < maxIndex)) { temp.localPosition = pos; //设置Item内容 UpdateItem(temp, i, realIndex); } } if (distance > extents) { Vector2 pos = temp.localPosition; pos.y -= extents * 2f; int x = (int)Mathf.Ceil(-pos.y / cellHeight) - 1;//行号 int y = (int)Mathf.Ceil(pos.x / cellWidth) - 1;//列号 int realIndex; if (arrangeType == Arrangement.Horizontal) realIndex = x * viewCount + y; else realIndex = x + viewCount * y; if (minIndex == maxIndex || (realIndex >= minIndex && realIndex < maxIndex)) { UpdateRectsize(pos); temp.localPosition = pos; //设置Item内容 UpdateItem(temp, i, realIndex); } } if (cullContent)//设置裁剪部分是否隐藏 { Vector2 pos = temp.localPosition; temp.gameObject.SetActive((pos.y > min && pos.y < max) ? true : false); } } } } void UpdateItem(Transform item, int index, int realIndex) { // LogHelper.Log(item + "----"+index +"----"+realIndex); if (onInitializeItem != null) { onInitializeItem(item.gameObject, index, realIndex); } } }