c1_unity/Assets/Scripts/Component/UI/ScrollRectCenter/ScrollRectCenterController.cs
2023-04-03 11:04:31 +08:00

571 lines
18 KiB
C#

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<CellObj> cachedCellList = new List<CellObj>();//缓存cellObj
List<CellObj> allCells = new List<CellObj>();
bool initedCacheRoot;
int objectIndex = 0;
protected int selectedIndex = 0;
private Vector3 currentVelocity = Vector3.zero;
//lua接口
public Action<int, int> luaRefreshAction;
public Action<GameObject> luaInstantiateCellAction;
public Action<bool, int> luaSetSelectedAction;
public Action<int> luaOnCenterAction;
public Action<int> luaOnLeaveCenterAction;
public Action luaOnBeginDragAction;
public Action luaOnEndDragAction;
private int index;
private ScrollRect cacheScrollRect;
private ScrollRect scrollRect
{
get
{
if (null == cacheScrollRect)
{
cacheScrollRect = GetComponent<ScrollRect>();
}
return cacheScrollRect;
}
}
private LayoutGroup cacheLayoutGroup;
private LayoutGroup layoutGroup
{
get
{
if (null == cacheLayoutGroup)
{
cacheLayoutGroup = scrollRect.content.GetComponent<LayoutGroup>();
}
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<RectTransform>();
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<GameObject> action)
{
luaInstantiateCellAction = action;
}
public void AddRefreshAction(Action<int, int> action)
{
luaRefreshAction = action;
}
public void AddSetSelectedAction(Action<bool, int> action)
{
luaSetSelectedAction = action;
}
public void AddOnCenterAction(Action<int> action)
{
luaOnCenterAction = action;
}
public void AddOnLeaveCenterAction(Action<int> 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();
}
/// <summary>
/// 有距离移动的时候更新 竖直方向
/// </summary>
public void OnUpdatePositionVer()
{
OnUpdateItem();
}
/// <summary>
/// 有距离移动的时候更新 水平方向
/// </summary>
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();
}
/// <summary>
/// 计算面板移动的位置
/// </summary>
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);
}
}
/// <summary>
/// 距离最近 centerTransform 的子物体索引
/// </summary>
/// <returns></returns>
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;
}
/// <summary>
/// 计算缩放的范围
/// </summary>
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;
}
}
/// <summary>
/// 计算单个cell的间距
/// </summary>
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;
}
}
/// <summary>
/// 更新 中心 子物体 位置
/// </summary>
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);
}
}
}
/// <summary>
/// 设置 子物体位置
/// </summary>
/// <param name="index"></param>
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;
}
}
}