| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
- using UnityEngine.Events;
- using UnityEngine.EventSystems;
- namespace JC
- {
- public class ScrollPanel : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerDownHandler, IPointerUpHandler
- {
- //public enum scrollAlignment
- //{
- // Upper,
- // Middle,
- // Lower
- //}
- public enum InitType {
- Statics, Dynamic
- }
- public InitType initType = InitType.Statics;
- ScrollRect _scrollRect;
- RectTransform _rectTransform;
- ScrollRect scrollRect {
- get {
- if (!_scrollRect)
- {
- _scrollRect = this.GetComponent<ScrollRect>();
- }
- return _scrollRect;
- }
- }
- RectTransform rectTransform {
- get {
- if (!_rectTransform)
- {
- _rectTransform = this.GetComponent<RectTransform>();
- }
- return _rectTransform;
- }
- }
- //偏移量
- public int offset = 0;
- //解决【Content节点的AnchorPresets在Inspector中设置成了Center,但运行时的效果却是LeftTop】的问题。
- Vector3 contentPosition {
- get {
- Vector3 v3 = scrollRect.content.localPosition;
- v3.x -= rectTransform.sizeDelta.x / 2 + offset;
- v3.y += rectTransform.sizeDelta.y / 2 ;
- return v3;
- }
- set {
- value.x += rectTransform.sizeDelta.x / 2 + offset;
- value.y -= rectTransform.sizeDelta.y / 2;
- scrollRect.content.localPosition = value;
- }
- }
- public List<RectTransform> itemList = new List<RectTransform>();
- RectTransform minItem {
- get {
- RectTransform bestItem = null;
- foreach (RectTransform item in itemList)
- {
- if (!bestItem || item.localPosition.x < bestItem.localPosition.x)
- {
- bestItem = item;
- }
- }
- return bestItem;
- }
- }
- RectTransform maxItem {
- get {
- RectTransform bestItem = null;
- foreach (RectTransform item in itemList)
- {
- if (!bestItem || item.localPosition.x > bestItem.localPosition.x)
- {
- bestItem = item;
- }
- }
- return bestItem;
- }
- }
- public int startIndex = 0;
- public int spacing = 0;
- public bool openReceiveItemViewInfo = false;
- public UnityEvent<RectTransform, Vector3, Vector2> onReceiveItemViewInfo;
- [Tooltip("以下节点将作为预制体,不加入ItemList中作为滚动内容,组件初始化时会隐藏预制体。")]
- int currentItemIndex = -1;
- void SetCurrentItemIndex(int index)
- {
- if (index != currentItemIndex)
- {
- currentItemIndex = index;
- onItemChange.Invoke(itemList[index], index);
- }
- }
- public UnityEvent<RectTransform, int> onItemChange;
- public List<GameObject> prefabs;
- void Start()
- {
- for (int i = 0; i < scrollRect.content.childCount; i++)
- {
- RectTransform item = scrollRect.content.GetChild(i).GetComponent<RectTransform>();
- if (prefabs.Contains(item.gameObject)) {
- item.gameObject.SetActive(false);
- } else {
- if (initType == InitType.Statics)
- {
- AddItem(item);
- }
- }
- }
- UpdateItems();
- SelectItemByStartIndex();
- }
- public void SelectItemByStartIndex()
- {
- if (startIndex >= 0 && startIndex < itemList.Count) {
- SetCurrentItemIndex(startIndex);
- MoveItemToCenter(itemList[startIndex]);
- }
- }
- bool snapping = false;
- int snapIndex = 0;
- void Update()
- {
- if (snapping) {
- if (snapIndex >= 0 && snapIndex < itemList.Count) {
- RectTransform item = itemList[snapIndex];
- // Debug.Log("snapIndex:"+ snapIndex);
- MoveItemToCenter(item);
- } else if (snapIndex >= itemList.Count) {
- snapIndex = itemList.Count - 1;
- }
- }
- }
- public void UpdateItems()
- {
- if (itemList.Count == 0) return;
- if (!scrollRect.horizontal) return;
- RectTransform minItemRecord = minItem;
- RectTransform maxItemRecord = maxItem;
- float centerX = -contentPosition.x;
- float deltaForMin = Mathf.Abs(minItemRecord.localPosition.x - centerX);
- float deltaForMax = Mathf.Abs(maxItemRecord.localPosition.x - centerX);
- if (deltaForMin < deltaForMax) {
- RectTransform item = minItemRecord;
- while (item && IsInMinBound(item))
- {
- //Debug.Log("next==== -1");
- item = RenderNextItem(item, -1);
- }
- } else if (deltaForMax < deltaForMin) {
- RectTransform item = maxItemRecord;
- while (item && IsInMaxBound(item))
- {
- //Debug.Log("next====1");
- item = RenderNextItem(item, 1);
- }
- }
-
- if (openReceiveItemViewInfo)
- {
- Vector3 contentPoint = contentPosition;
- foreach (var item in itemList)
- {
- Vector3 positinInView = contentPoint + item.localPosition;
- Vector2 viewSize = rectTransform.sizeDelta;
- onReceiveItemViewInfo.Invoke(item, positinInView, viewSize);
- }
- }
- }
- bool IsInMinBound(RectTransform item)
- {
- return item.localPosition.x + contentPosition.x - item.sizeDelta.x / 2
- > -rectTransform.sizeDelta.x / 2;
- }
- bool IsInMaxBound(RectTransform item)
- {
- return item.localPosition.x + contentPosition.x + item.sizeDelta.x / 2
- < rectTransform.sizeDelta.x / 2;
- }
- bool IsOutBound(RectTransform item)
- {
- if (item.localPosition.x + contentPosition.x + item.sizeDelta.x / 2
- < -rectTransform.sizeDelta.x / 2) return true;
- if (item.localPosition.x + contentPosition.x - item.sizeDelta.x / 2
- > rectTransform.sizeDelta.x / 2) return true;
- return false;
- }
- RectTransform RenderNextItem(RectTransform item, int relativeIndex) {
- int index = itemList.IndexOf(item);
- index += relativeIndex;
- if (index < 0) {
- index = itemList.Count - 1;
- } else if (index >= itemList.Count) {
- index = 0;
- }
- //Debug.Log("index====:"+ index);
- RectTransform targetItem = itemList[index];
- if (IsOutBound(targetItem)) {
- Vector3 position = targetItem.localPosition;
- position.x = item.localPosition.x + relativeIndex * (targetItem.sizeDelta.x + spacing);
- targetItem.localPosition = position;
- return targetItem;
- }
- return null;
- }
- public void AddItem(RectTransform item)
- {
- if (scrollRect.horizontal)
- {
- item.SetParent(scrollRect.content);
- Vector3 position = item.localPosition;
- position.x = 0;
- if (itemList.Count > 0) {
- RectTransform lastItem = itemList[itemList.Count - 1];
- foreach (RectTransform child in itemList)
- {
- if (child.localPosition.x > lastItem.localPosition.x) {
- Vector3 childPosition = child.localPosition;
- childPosition.x += child.sizeDelta.x + spacing;
- child.localPosition = childPosition;
- }
- }
- position.x = lastItem.localPosition.x + item.sizeDelta.x + spacing;
- }
- position.y = 0;
- position.z = 0;
- item.localPosition = position;
- }
- itemList.Add(item);
- }
- public void RemoveItem(RectTransform item)
- {
- if (itemList.IndexOf(item) == currentItemIndex) {
- currentItemIndex = -1;
- }
- itemList.Remove(item);
- if (scrollRect.horizontal)
- {
- foreach (RectTransform child in itemList)
- {
- if (child.localPosition.x > item.localPosition.x) {
- Vector3 childPosition = child.localPosition;
- childPosition.x -= child.sizeDelta.x + spacing;
- child.localPosition = childPosition;
- }
- }
- }
- Destroy(item.gameObject);
- }
- public void ClearItems()
- {
- foreach (var item in itemList)
- {
- Destroy(item.gameObject);
- }
- itemList.Clear();
- currentItemIndex = -1;
- }
- RectTransform FindNearestItemToCenter()
- {
- RectTransform bestItem = null;
- Vector3 position = contentPosition;
- foreach(RectTransform item in itemList)
- {
- if (
- !bestItem ||
- Mathf.Abs(item.localPosition.x + position.x - 0)
- < Mathf.Abs(bestItem.localPosition.x + position.x - 0)
- ) {
- bestItem = item;
- }
- }
- return bestItem;
- }
- public void MoveNearestItemToCenter()
- {
- if (itemList.Count == 0) return;
- RectTransform item = FindNearestItemToCenter();
- snapping = true;
- snapIndex = itemList.IndexOf(item);
- SetCurrentItemIndex(snapIndex);
- }
- void MoveItemToCenter(RectTransform item)
- {
- Vector3 position = contentPosition;
- position.x -= (item.localPosition.x + contentPosition.x);
- if (Mathf.Abs(contentPosition.x - position.x) < 1) {
- snapping = false;
- }
- contentPosition = snapping ? Vector3.Lerp(contentPosition, position, Time.deltaTime * 5) : position;
- UpdateItems();
- }
- public void MoveNextToCenter(int direction)
- {
- if (itemList.Count == 0) return;
- if (direction == 0)
- {
- MoveNearestItemToCenter();
- return;
- }
- RectTransform item = FindNearestItemToCenter();
- int index = itemList.IndexOf(item);
- if (direction < 0)
- {
- index--;
- //int nextIndex = index - Mathf.Abs(direction);
- //index = nextIndex >= 0 ? nextIndex : itemList.Count + nextIndex;
- }
- if (direction > 0)
- {
- //int nextIndex = index + Mathf.Abs(direction);
- // index = nextIndex < itemList.Count ? nextIndex : nextIndex - itemList.Count;
- index++;
- }
- if (index < 0)
- {
- index = itemList.Count - 1;
- }
- if (index >= itemList.Count)
- {
- index = 0;
- }
- //item = itemList[index];
- snapping = true;
- snapIndex = index;
- SetCurrentItemIndex(snapIndex);
- }
- public void OnBeginDrag(PointerEventData eventData) {
- snapping = false;
- }
- public void OnDrag(PointerEventData eventData)
- {
- UpdateItems();
- }
- public void OnEndDrag(PointerEventData eventData)
- {
- MoveNearestItemToCenter();
- }
- public void OnPointerDown(PointerEventData eventData) {
- snapping = false;
- }
- public void OnPointerUp(PointerEventData eventData) {
- snapping = true;
- }
- }
- }
|