using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System; namespace BF { [RequireComponent(typeof(ScrollRectCenter))] public class ScrollRectCenterController : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { public BFCell bfCell; public RectTransform centerTransform;//基准中心位置 private int indexCenter; public bool isDrag; public float targetPosition; public float lastDragPoint;//上一次移动位置 public bool moveToImmediately = false; // 缩放范围 public float impactScaleRang = 0.8f; // cell 滚动缩放类型 public int CellScrollScaleType = 1; public float CellScrollScaleDistance = 0.0f; private int totalCount; RectTransform cacheRoot;//缓存root List cachedCellList = new List();//缓存cellObj List allCells = new List(); bool initedCacheRoot; int objectIndex = 0; protected int selectedIndex = 0; private Vector3 currentVelocity = Vector3.zero; //lua接口 public Action luaRefreshAction; public Action luaInstantiateCellAction; public Action luaSetSelectedAction; public Action luaOnCenterAction; public Action luaOnLeaveCenterAction; public Action luaOnBeginDragAction; public Action luaOnEndDragAction; private int index; private ScrollRect cacheScrollRect; private ScrollRect scrollRect { get { if (null == cacheScrollRect) { cacheScrollRect = GetComponent(); } return cacheScrollRect; } } private LayoutGroup cacheLayoutGroup; private LayoutGroup layoutGroup { get { if (null == cacheLayoutGroup) { cacheLayoutGroup = scrollRect.content.GetComponent(); } return cacheLayoutGroup; } } void Awake() { if (bfCell.gameObject.activeSelf) { bfCell.gameObject.SetActive(false); } if (!initedCacheRoot) InitCacheRoot(); } void InitCacheRoot() { var cacheTransform = transform.Find(StringConst.CACHE_ROOT_NAME); if (cacheTransform == null) { GameObject go = new GameObject(StringConst.CACHE_ROOT_NAME); cacheRoot = go.AddComponent(); cacheRoot.SetParent(transform); cacheRoot.localScale = new Vector3(1, 1, 1); cacheRoot.localPosition = Vector3.zero; go.SetActive(false); } if (cacheRoot == null) cacheRoot = cacheTransform.transform as RectTransform; initedCacheRoot = true; } public void AddOnInstantiateCellAction(Action action) { luaInstantiateCellAction = action; } public void AddRefreshAction(Action action) { luaRefreshAction = action; } public void AddSetSelectedAction(Action action) { luaSetSelectedAction = action; } public void AddOnCenterAction(Action action) { luaOnCenterAction = action; } public void AddOnLeaveCenterAction(Action action) { luaOnLeaveCenterAction = action; } public void AddOnBeginDragAction(Action action) { luaOnBeginDragAction = action; } public void AddOnEndDragAction(Action action) { luaOnEndDragAction = action; } // **************************************************************************** public void InitComponent() { StartCoroutine(RefreshScrollview()); } protected IEnumerator RefreshScrollview() { yield return new WaitForEndOfFrame(); OnUpdatePositionHor(); OnUpdatePositionVer(); } /// /// 有距离移动的时候更新 竖直方向 /// public void OnUpdatePositionVer() { OnUpdateItem(); } /// /// 有距离移动的时候更新 水平方向 /// public void OnUpdatePositionHor() { OnUpdateItem(); } private void OnUpdateItem() { for (int i = 0; i < scrollRect.content.childCount; i++) { UpdateItem(scrollRect.content.GetChild(i), i); } } private void UpdateItem(Transform item, int index) { if (scrollRect.content.childCount == 0) return; Vector2 itemPos = (item.transform as RectTransform).anchoredPosition; Vector2 centerPos = (centerTransform.transform as RectTransform).anchoredPosition; float distance = 0; if (scrollRect.horizontal) distance = Mathf.Abs(Mathf.Abs(item.position.x) - Mathf.Abs(centerTransform.position.x)) * 100; if (scrollRect.vertical) distance = Mathf.Abs(Mathf.Abs(item.position.y) - Mathf.Abs(centerTransform.position.y)) * 100; // 中间的一倍大小,其他的大小一致 if (CellScrollScaleType == 1) { if(CellScrollScaleDistance > 0.01) { if(distance > CellScrollScaleDistance) { distance = CellScrollScaleDistance; } float scale = 1 - (1 - impactScaleRang)*distance/CellScrollScaleDistance; item.localScale = Vector3.one * scale; } else { if(CellDistance > 0.1) { if(distance > CellDistance) { distance = CellDistance; } float scale = 1 - (1 - impactScaleRang)*distance/CellDistance; item.localScale = Vector3.one * scale; } } } else // 中间的一倍大小,其他的距离越远越小 { float scale = RatioScaleRange / (distance + RatioScaleRange); item.localScale = Vector3.one * scale; } } public void OnBeginDrag(PointerEventData eventData) { isDrag = true; luaOnBeginDragAction?.Invoke(); } public void OnDrag(PointerEventData eventData) { //更新center index OnUpdateItemCenter(); } public void OnEndDrag(PointerEventData eventData) { OnUpdateContentPosition(); isDrag = false; luaOnEndDragAction?.Invoke(); } /// /// 计算面板移动的位置 /// private void OnUpdateContentPosition() { Vector3 position = scrollRect.content.GetChild(indexCenter).position; RectTransform rectTransform = scrollRect.content.GetChild(indexCenter).transform as RectTransform; if (scrollRect.horizontal) { targetPosition = -rectTransform.sizeDelta.x * (0.5f + indexCenter) - ((GridLayoutGroup)layoutGroup).spacing.x * (indexCenter); } else if (scrollRect.vertical) { targetPosition = rectTransform.sizeDelta.y * (0.5f + indexCenter) + ((GridLayoutGroup)layoutGroup).spacing.y * (indexCenter); } } /// /// 距离最近 centerTransform 的子物体索引 /// /// private int ResoultRecentItemIndex() { if (centerTransform == null) { BFLog.LogError("centerTransform Can not NUll"); } int index = 0; if (scrollRect.horizontal) { float offSet = Mathf.Abs(centerTransform.transform.position.x - scrollRect.content.GetChild(0).transform.position.x); for (int i = 0; i < scrollRect.content.childCount; i++) { float offsetTemp = Mathf.Abs(centerTransform.transform.position.x - scrollRect.content.GetChild(i).transform.position.x); if (offsetTemp < offSet) { index = i; offSet = offsetTemp; } } } if (scrollRect.vertical) { float offSet = Mathf.Abs(centerTransform.transform.position.y - scrollRect.content.GetChild(0).transform.position.y); for (int i = 0; i < scrollRect.content.childCount; i++) { float offsetTemp = Mathf.Abs(centerTransform.transform.position.y - scrollRect.content.GetChild(i).transform.position.y); if (offsetTemp < offSet) { index = i; offSet = offsetTemp; } } } return index; } /// /// 计算缩放的范围 /// private float RatioScaleRange { get { float range = 1; var rectTransform = scrollRect.content.transform as RectTransform; if (scrollRect.vertical) { range = (rectTransform.sizeDelta.y / scrollRect.content.childCount) * impactScaleRang; } else { range = (rectTransform.sizeDelta.x / scrollRect.content.childCount) * impactScaleRang; } return range; } } /// /// 计算单个cell的间距 /// private float CellDistance { get { float dis = 1; var rectTransform = scrollRect.content.transform as RectTransform; if (scrollRect.vertical) { dis = (rectTransform.sizeDelta.y + ((GridLayoutGroup)layoutGroup).spacing.y) / scrollRect.content.childCount; } else { dis = (rectTransform.sizeDelta.x + ((GridLayoutGroup)layoutGroup).spacing.x) / scrollRect.content.childCount; } return dis; } } /// /// 更新 中心 子物体 位置 /// private void OnUpdateItemCenter() { var targetIndex = ResoultRecentItemIndex(); if (this.indexCenter != targetIndex) { int lastIndexCenter = this.indexCenter; this.indexCenter = targetIndex; if (luaOnCenterAction != null) { luaOnCenterAction(this.indexCenter); } if (luaOnLeaveCenterAction != null) { luaOnLeaveCenterAction(lastIndexCenter); } } } /// /// 设置 子物体位置 /// /// public void SetUpdateItemCenter(int index, bool immediately = false) { if (immediately) { SetItemCenter(index); } else { StartCoroutine(OnSetItemCenter(index)); } moveToImmediately = immediately; } private IEnumerator OnSetItemCenter(int index) { yield return new WaitForEndOfFrame(); SetItemCenter(index); } private void SetItemCenter(int index) { bool isInitStatus = (index == 0 && this.indexCenter == 0);//初始化的状态 if (isInitStatus) { if (luaOnCenterAction != null) { luaOnCenterAction(this.indexCenter); } } if (this.indexCenter != index) { int lastIndexCenter = this.indexCenter; this.indexCenter = index; if (luaOnCenterAction != null) { luaOnCenterAction(this.indexCenter); } if (luaOnLeaveCenterAction != null) { luaOnLeaveCenterAction(lastIndexCenter); } } OnUpdateContentPosition(); } public void MoveLeft() { MoveTo(this.indexCenter - 1); } public void MoveRight() { MoveTo(this.indexCenter + 1); } public void MoveTo(int index, bool immediately = false) { SetUpdateItemCenter(index, immediately); } public void SetTotalCount(int totalCount) { this.totalCount = totalCount; } public void SetScaleRatio(float ratio) { this.impactScaleRang = ratio; } //同scrollrect public void RefillCells(int centerIndex) { if (allCells.Count > 0) { while (allCells.Count != 0) { CacheCell(allCells[allCells.Count - 1]); allCells.RemoveAt(allCells.Count - 1); } } //create 直接创建全部 for (int i = 0; i < totalCount; i++) { InstantiateNextItem(i); } InitComponent(); SetUpdateItemCenter(centerIndex); } public void RefreshAll() { for (int index = 0; index < totalCount; index++) { CellObj cell = allCells[index]; int objIndex = cell.objectIndex; luaRefreshAction?.Invoke(index, objIndex); } } void CacheCell(CellObj cell) { if (cell != null) { cell.gameObject.transform.SetParent(cacheRoot); cachedCellList.Add(cell); } } protected CellObj GetCell(GameObject gameObject) { int count = allCells.Count; for (int i = count - 1; i >= 0; i--) { if (allCells[i].gameObject == gameObject) return allCells[i]; } var cell = new CellObj(); objectIndex++; cell.objectIndex = objectIndex; cell.gameObject = gameObject; cell.index = 1; allCells.Add(cell); return cell; } // 计算初始化时,真实需要生成的cell数量 private int CalculateRealCellNum(RectTransform item) { var maskRect = ((RectTransform)this.transform).rect; float maskSize = scrollRect.horizontal ? maskRect.width : maskRect.height; float itemSize = scrollRect.horizontal ? item.sizeDelta.x : item.sizeDelta.y; float space = scrollRect.horizontal ? ((GridLayoutGroup)layoutGroup).spacing.x : ((GridLayoutGroup)layoutGroup).spacing.y; return Mathf.Min(Mathf.CeilToInt(maskSize / (itemSize + space)) + 1, this.totalCount); } // ----------------------------------------------------------- RectTransform InstantiateNextItem(int index) { RectTransform nextItemTrans = null; CellObj nextCell = null; if (totalCount < index + 1) return null; if (cachedCellList.Count > 0) { int cachedCellIndex = cachedCellList.Count - 1; nextItemTrans = cachedCellList[cachedCellIndex].gameObject.transform as RectTransform; nextCell = cachedCellList[cachedCellIndex]; cachedCellList.RemoveAt(cachedCellIndex); nextItemTrans.transform.SetParent(scrollRect.content, false); nextItemTrans.gameObject.SetActive(true); } else if (nextItemTrans == null) { nextItemTrans = Instantiate(bfCell.CachedRectTransform); nextItemTrans.SetParent(scrollRect.content, false); nextItemTrans.gameObject.SetActive(true); nextCell = new CellObj(); objectIndex++; nextCell.objectIndex = objectIndex; nextCell.gameObject = nextItemTrans.gameObject; luaInstantiateCellAction?.Invoke(nextCell.gameObject); } if (nextItemTrans == null) return null; nextCell.index = index; nextCell.gameObject.name = StringConst.GetScrollRectCellName(index); allCells.Add(nextCell); luaRefreshAction?.Invoke(index, nextCell.objectIndex); return nextItemTrans; } public int GetSelectedIndex() { return selectedIndex; } public void SetSelected(int index) { selectedIndex = index; int count = allCells.Count; for (int i = 0; i < count; i++) if (luaSetSelectedAction != null) luaSetSelectedAction(allCells[i].index == index, allCells[i].objectIndex); } public void ResetCenterIndex() { this.indexCenter = 0; } void OnDestroy() { luaInstantiateCellAction = null; luaRefreshAction = null; luaSetSelectedAction = null; luaOnCenterAction = null; luaOnLeaveCenterAction = null; } } }