571 lines
18 KiB
C#
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;
|
|
}
|
|
}
|
|
} |