NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/GameWrapper/UIScrollFocusHelper.cs

295 lines
7.9 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
2024-03-08 12:20:00 +08:00
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
2024-03-08 12:20:00 +08:00
using DG.Tweening;
[RequireComponent(typeof(ScrollRect))]
public class UIScrollFocusHelper: MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public GameObject itemTemplate;
public Transform focusItemTrans;
private ScrollRect _scrollRect;
private GameObject _content;
private bool _isVertical;
private List<GameObject> _itemList;
private Delegate _focusItemFunc;
private Delegate _unFocusItemFunc;
2024-03-08 12:20:00 +08:00
private int _curIndex;
private List<float> _childPosXList;
private float _centerPosX;
private float _spacing;
private Vector2 _lastFrameContentPos;
private RectTransform _contentRectTrans;
private int _maxIndex;
private int _minIndex;
private bool _isPlayingMove;
public int CurIndex => _curIndex;
#region DragHandler
public void OnBeginDrag(PointerEventData eventData)
{
}
public void OnDrag(PointerEventData eventData)
{
2024-03-08 12:20:00 +08:00
if (_itemList == null || _itemList.Count <= 0)
{
return;
}
2024-03-08 12:20:00 +08:00
_SetCurIndexFocus();
}
public void OnEndDrag(PointerEventData eventData)
{
}
#endregion
#region UnityEvent Function
private void Awake()
{
_scrollRect = gameObject.GetComponent<ScrollRect>();
if (!_scrollRect)
{
DebugUtil.LogError("UIScrollFocusHelper Error!!! 请检查节点是否绑定ScrollRect组件!!! ");
return;
}
_content = _scrollRect.transform.Find("Viewport/Content").gameObject;
bool isVertical = true;
if (_scrollRect.horizontal)
{
if (_scrollRect.vertical)
{
DebugUtil.LogError("UIScrollFocusHelper Error!!! 仅支持ScrollRect单方向拖动!!! ");
return;
}
isVertical = false;
}
_isVertical = isVertical;
2024-03-08 12:20:00 +08:00
_contentRectTrans = _content.GetComponent<RectTransform>();
var layoutGroup = _GetContentLayoutGroup();
if (layoutGroup)
{
if (_isVertical)
{
2024-03-08 12:20:00 +08:00
//layoutGroup = (VerticalLayoutGroup)layoutGroup;
var lay = layoutGroup as VerticalLayoutGroup;
if (lay)
{
_spacing = lay.spacing;
}
_centerPosX = _scrollRect.GetComponent<RectTransform>().rect.height * 0.5f;
}
else
{
2024-03-08 12:20:00 +08:00
//layoutGroup = (HorizontalLayoutGroup)layoutGroup;
var lay = layoutGroup as HorizontalLayoutGroup;
if (lay)
{
_spacing = lay.spacing;
}
_centerPosX = _scrollRect.GetComponent<RectTransform>().rect.width * 0.5f;
}
}
2024-03-08 12:20:00 +08:00
_scrollRect.onValueChanged.AddListener(_RefreshCurIndex);
_isPlayingMove = false;
}
#endregion
private LayoutGroup _GetContentLayoutGroup()
{
if (!_content)
{
DebugUtil.LogError("UIScrollFocusHelper Error!!! 请检查ScrollRect的Content节点!!! ");
}
var layoutGroup = _content.GetComponent<LayoutGroup>();
return layoutGroup;
}
2024-03-08 12:20:00 +08:00
private void _RefreshCurIndex(Vector2 pos)
{
if (_itemList == null || _itemList.Count <= 0)
{
return;
}
_SetCurIndexFocus();
}
private void _SetCurIndexFocus()
{
var curIdx = FindClosestIndex();
if (_curIndex != curIdx)
{
_curIndex = curIdx;
var item = _itemList[curIdx];
if (_focusItemFunc != null)
{
if (_focusItemFunc is Action<GameObject> action)
{
action.Invoke(item);
}
}
if (_unFocusItemFunc != null)
{
for (int i = 0; i < _itemList.Count; i++)
{
if (i != curIdx)
{
if (_unFocusItemFunc is Action<GameObject> unFocusAction)
{
unFocusAction.Invoke(_itemList[i]);
}
}
}
}
}
}
private void _SetCachePosData()
{
if (_itemList == null || _itemList.Count <= 0)
{
return;
}
if (_childPosXList == null)
{
_childPosXList = new List<float>();
}
else
{
_childPosXList.Clear();
}
var childPosX = itemTemplate.GetComponent<RectTransform>().rect.width * 0.5f;
_childPosXList.Add(childPosX);
for (int i = 1; i < _itemList.Count; i++)
{
childPosX = childPosX + itemTemplate.GetComponent<RectTransform>().rect.width + _spacing;
_childPosXList.Add(childPosX);
}
}
private int FindClosestIndex()
{
int retIndex = 0;
var contentPosX = _contentRectTrans.localPosition.x;
var curCenterPosX = _centerPosX - contentPosX;
var minDis = itemTemplate.GetComponent<RectTransform>().rect.width;
for(int i = 0; i < _childPosXList.Count; i++)
{
var distance = Mathf.Abs(curCenterPosX - _childPosXList[i]);
if (distance < minDis)
{
minDis = distance;
retIndex = i;
}
}
return retIndex;
}
private async void _DoMoveContent(bool isRight)
{
2024-03-08 12:20:00 +08:00
if (isRight)
{
_isPlayingMove = true;
var curIndex = _curIndex + 1;
if (curIndex < _maxIndex)
{
//计算相邻两个item之间的距离
var oldPosX = _childPosXList[_curIndex];
_curIndex++;
var newPosX = _childPosXList[_curIndex];
var distance = Mathf.Abs(oldPosX - newPosX);
//播放移动动画
var curPos = _contentRectTrans.localPosition;
var childPosX = curPos.x - distance;
var newPos = new Vector3(childPosX, curPos.y, curPos.z);
_contentRectTrans.DOLocalMove(newPos, 0.75f);
UniTask.Delay(750);
_isPlayingMove = false;
}
}
else
{
var curIndex = _curIndex - 1;
if (curIndex > _minIndex)
{
//计算相邻两个item之间的距离
var oldPosX = _childPosXList[_curIndex];
_curIndex--;
var newPosX = _childPosXList[_curIndex];
var distance = Mathf.Abs(oldPosX - newPosX);
//播放移动动画
var curPos = _contentRectTrans.localPosition;
var childPosX = curPos.x + distance;
var newPos = new Vector3(childPosX, curPos.y, curPos.z);
_contentRectTrans.DOLocalMove(newPos, 0.75f);
UniTask.Delay(750);
_isPlayingMove = false;
}
}
}
#region API
2024-03-08 12:20:00 +08:00
public void Init()
{
_SetCachePosData();
_SetCurIndexFocus();
}
public void SetData(List<GameObject> list, int maxIndex, int minIndex = 0)
{
_itemList = list;
2024-03-08 12:20:00 +08:00
_maxIndex = maxIndex;
_minIndex = minIndex;
}
public void SetFocusItemFunc(Action<GameObject> action)
{
_focusItemFunc = action;
}
public void SetUnFocusItemFunc(Action<GameObject> action)
{
_unFocusItemFunc = action;
}
2024-03-08 12:20:00 +08:00
public void ChangeIndex(bool isAdd)
{
if (_isPlayingMove)
{
return;
}
2024-03-08 12:20:00 +08:00
_DoMoveContent(isAdd);
}
#endregion
}