using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; public enum ScrollDir { Horizontal, Vertical } public class ScrollRectCenter : MonoBehaviour , IEndDragHandler,IDragHandler,IBeginDragHandler { public ScrollDir Dir = ScrollDir.Horizontal; public event Action OnFinalSelect; /// /// 是否正在居中 /// private bool _isCentering = false; /// /// 居中过程移动速度 /// public float MoveToCenterSpeed = 10f; private ScrollRect _scrollView; private Transform _content; private List _childrenPos = new List(); private float _targetPos; /// /// 当前中心child索引 /// private int _curCenterChildIndex = -1; private bool inited = false; /// /// 当前中心ChildItem /// public GameObject CurCenterChildItem { get { GameObject centerChild = null; if (_content != null && _curCenterChildIndex >= 0 && _curCenterChildIndex < _content.childCount) { centerChild = _content.GetChild(_curCenterChildIndex).gameObject; } return centerChild; } } void Awake() { if (inited) return; inited = true; _scrollView = GetComponent(); if (_scrollView == null) { Debug.LogError("ScrollRect is null"); return; } _content = _scrollView.content; Recalculate(); /*LayoutGroup layoutGroup = null; layoutGroup = _content.GetComponent(); if (layoutGroup == null) { Debug.LogError("LayoutGroup component is null"); } _scrollView.movementType = ScrollRect.MovementType.Unrestricted; float spacing = 0f; //根据dir计算坐标,Horizontal:存x,Vertical:存y switch (Dir) { case ScrollDir.Horizontal: if (layoutGroup is HorizontalLayoutGroup) { float childPosX = _scrollView.GetComponent().rect.width * 0.5f - GetChildItemWidth(0) * 0.5f; spacing = (layoutGroup as HorizontalLayoutGroup).spacing; _childrenPos.Add(childPosX); for (int i = 1; i < _content.childCount; i++) { childPosX -= GetChildItemWidth(i) * 0.5f + GetChildItemWidth(i - 1) * 0.5f + spacing; _childrenPos.Add(childPosX); } } else if (layoutGroup is GridLayoutGroup) { GridLayoutGroup grid = layoutGroup as GridLayoutGroup; float childPosX = _scrollView.GetComponent().rect.width * 0.5f - grid.cellSize.x * 0.5f; _childrenPos.Add(childPosX); for (int i = 0; i < _content.childCount - 1; i++) { childPosX -= grid.cellSize.x + grid.spacing.x; _childrenPos.Add(childPosX); } } else { Debug.LogError("Horizontal ScrollView is using VerticalLayoutGroup"); } break; case ScrollDir.Vertical: if (layoutGroup is VerticalLayoutGroup) { float childPosY = -_scrollView.GetComponent().rect.height * 0.5f + GetChildItemHeight(0) * 0.5f; spacing = (layoutGroup as VerticalLayoutGroup).spacing; _childrenPos.Add(childPosY); for (int i = 1; i < _content.childCount; i++) { childPosY += GetChildItemHeight(i) * 0.5f + GetChildItemHeight(i - 1) * 0.5f + spacing; _childrenPos.Add(childPosY); } } else if (layoutGroup is GridLayoutGroup) { GridLayoutGroup grid = layoutGroup as GridLayoutGroup; float childPosY = -_scrollView.GetComponent().rect.height * 0.5f + grid.cellSize.y * 0.5f; _childrenPos.Add(childPosY); for (int i = 1; i < _content.childCount; i++) { childPosY += grid.cellSize.y + grid.spacing.y; _childrenPos.Add(childPosY); } } else { Debug.LogError("Vertical ScrollView is using HorizontalLayoutGroup"); } break; }*/ } public void Recalculate()//重新计算 { _childrenPos.Clear(); LayoutGroup layoutGroup = null; layoutGroup = _content.GetComponent(); if (layoutGroup == null) { Debug.LogError("LayoutGroup component is null"); } _scrollView.movementType = ScrollRect.MovementType.Unrestricted; float spacing = 0f; //根据dir计算坐标,Horizontal:存x,Vertical:存y switch (Dir) { case ScrollDir.Horizontal: if (layoutGroup is HorizontalLayoutGroup) { float childPosX = _scrollView.GetComponent().rect.width * 0.5f - GetChildItemWidth(0) * 0.5f; spacing = (layoutGroup as HorizontalLayoutGroup).spacing; _childrenPos.Add(childPosX); for (int i = 1; i < _content.childCount; i++) { childPosX -= GetChildItemWidth(i) * 0.5f + GetChildItemWidth(i - 1) * 0.5f + spacing; _childrenPos.Add(childPosX); } } else if (layoutGroup is GridLayoutGroup) { GridLayoutGroup grid = layoutGroup as GridLayoutGroup; float childPosX = _scrollView.GetComponent().rect.width * 0.5f - grid.cellSize.x * 0.5f; _childrenPos.Add(childPosX); for (int i = 0; i < _content.childCount - 1; i++) { childPosX -= grid.cellSize.x + grid.spacing.x; _childrenPos.Add(childPosX); } } else { Debug.LogError("Horizontal ScrollView is using VerticalLayoutGroup"); } break; case ScrollDir.Vertical: if (layoutGroup is VerticalLayoutGroup) { float childPosY = -_scrollView.GetComponent().rect.height * 0.5f + GetChildItemHeight(0) * 0.5f; spacing = (layoutGroup as VerticalLayoutGroup).spacing; _childrenPos.Add(childPosY); for (int i = 1; i < _content.childCount; i++) { childPosY += GetChildItemHeight(i) * 0.5f + GetChildItemHeight(i - 1) * 0.5f + spacing; _childrenPos.Add(childPosY); } } else if (layoutGroup is GridLayoutGroup) { GridLayoutGroup grid = layoutGroup as GridLayoutGroup; float childPosY = -_scrollView.GetComponent().rect.height * 0.5f + grid.cellSize.y * 0.5f; _childrenPos.Add(childPosY); for (int i = 1; i < _content.childCount; i++) { childPosY += grid.cellSize.y + grid.spacing.y; _childrenPos.Add(childPosY); } } else { Debug.LogError("Vertical ScrollView is using HorizontalLayoutGroup"); } break; } } private float GetChildItemWidth(int index) { return (_content.GetChild(index) as RectTransform).sizeDelta.x; } private float GetChildItemHeight(int index) { return (_content.GetChild(index) as RectTransform).sizeDelta.y; } void Start () { } void Update () { if (_isCentering) { Vector3 v = _content.localPosition; switch (Dir) { case ScrollDir.Horizontal: v.x = Mathf.Lerp(_content.localPosition.x, _targetPos, MoveToCenterSpeed * Time.deltaTime); _content.localPosition = v; if (Math.Abs(_content.localPosition.x - _targetPos) < 0.01f) { _isCentering = false; } break; case ScrollDir.Vertical: v.y = Mathf.Lerp(_content.localPosition.y, _targetPos, MoveToCenterSpeed * Time.deltaTime); _content.localPosition = v; if (Math.Abs(_content.localPosition.y - _targetPos) < 0.01f) { _isCentering = false; } break; } } } public void OnDrag(PointerEventData eventData) { } public void OnEndDrag(PointerEventData eventData) { switch (Dir) { case ScrollDir.Horizontal: _targetPos = FindClosestChildPos(_content.localPosition.x, out _curCenterChildIndex); break; case ScrollDir.Vertical: _targetPos = FindClosestChildPos(_content.localPosition.y, out _curCenterChildIndex); if (OnFinalSelect != null) { OnFinalSelect(_curCenterChildIndex); } break; } _isCentering = true; } public void OnBeginDrag(PointerEventData eventData) { _isCentering = false; _curCenterChildIndex = -1; } private float FindClosestChildPos(float currentPos, out int curCenterChildIndex) { float closest = 0; float distance = Mathf.Infinity; curCenterChildIndex = -1; for (int i = 0; i < _childrenPos.Count; i++) { float p = _childrenPos[i]; float d = Mathf.Abs(p - currentPos); if (d < distance) { distance = d; closest = p; curCenterChildIndex = i; } } return closest; } public void SetCurrentIndex(int index) { Awake(); float p=_childrenPos[index]; _targetPos = p; _isCentering = true; } }