IndieGame/client/Assets/Ether/Scripts/Module/Extension/UGUI/ScrollView/ScrollViewGridEx.cs

336 lines
12 KiB
C#
Raw Normal View History

2024-10-11 10:12:15 +08:00
/********************************************************************
: ScrollViewGridEx.cs
:
: 1982614048@qq.com
: 2024/4/5 17:11
:
: 2024/04/23 09:21:55
:
*********************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Sirenix.OdinInspector;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Ether
{
public class ScrollViewGridEx : SerializedMonoBehaviour
{
public enum ScrollDirection
{
[InspectorName("从上到下")]
TopToDown,
[InspectorName("从下到上")]
DownToTop,
[InspectorName("从左到右")]
LeftToRight,
[InspectorName("从右到左")]
RightToLeft,
}
/// <summary>
/// 格子数据
/// </summary>
public class CellInfo
{
public int index;
public Vector3 pos; //已左上角为点
public GameObject item;
}
#region
private ScrollRect scrollRect;
public ScrollRect ScrollRect => scrollRect;
[ShowInInspector]
private RectTransform content;
[Tooltip("该属性优先"), LabelText("格子预制体")]
[ShowIf("@this.cellPrefabPath == null || this.cellPrefabPath == \"\"")]
public GameObject cellPrefab;
[Tooltip("格子预制体属性优先"), LabelText("格子预制体路径")]
[ShowIf("@this.cellPrefab == null")]
public string cellPrefabPath;
private ScrollDirection scrollDirection;
[SerializeField, ExposeProperty, Label("方向")]
public ScrollDirection Direction
{
get => scrollDirection;
set
{
scrollDirection = value;
ScrollRect scroll = GetComponent<ScrollRect>();
//Debug.LogError(scrollDirection);
switch (value)
{
case ScrollDirection.TopToDown:
case ScrollDirection.DownToTop:
scroll.horizontal = false;
scroll.vertical = true;
break;
case ScrollDirection.LeftToRight:
case ScrollDirection.RightToLeft:
scroll.horizontal = true;
scroll.vertical = false;
break;
default:
break;
}
}
}
[SerializeField, Label("一行或一列数量")]
private int rowOrColNum = 1;
[SerializeField, Label("间隔")]
private Vector2 specing;
#endregion
private void Awake()
{
scrollRect = GetComponent<ScrollRect>();
if (scrollRect == null)
{
Debug.LogError("该组件需要对应的ScrollRect! 请检查!!!");
return;
}
if (content == null)
{
content = scrollRect?.content;
}
if (content == null)
{
Transform viewport = scrollRect?.viewport;
content = viewport != null ? viewport?.GetChild(0).GetComponent<RectTransform>() : null;
}
if (content == null)
{
Debug.LogError("获取不到对应的ScrollView中的content! 请检查!!!");
return;
}
content.anchorMin = new Vector2(0, 1);
content.anchorMax = new Vector2(0, 1);
if (cellPrefab == null)
{
cellPrefab = LoaderTools.LoadAsset<GameObject>(cellPrefabPath);
}
if (cellPrefab == null)
{
Debug.LogError("获取不到对应的格子预制体! 请检查!!!");
return;
}
cellPrefab.SetActive(false);
scrollRect.onValueChanged.RemoveAllListeners();
scrollRect.onValueChanged.AddListener(ScrollOnDragListener);
}
Action<GameObject, int> actionEvent;
List<CellInfo> cellInfoList = new List<CellInfo>();
public void Init(Action<GameObject, int> dataAction, int dataMaxNum = -1)
{
cellInfoList.Clear();
actionEvent = dataAction;
if (dataMaxNum != -1)
{
RefreshData(dataMaxNum);
}
}
public void RefreshData(int dataMaxNum)
{
if (cellPrefab == null)
{
Debug.LogError("获取不到对应的格子预制体! 请检查!!!");
return;
}
foreach (CellInfo info in cellInfoList)
{
if (info.item != null)
{
info.item.PushPool();
}
info.PushPool();
}
for (int i = 0; i < dataMaxNum; i++)
{
CellInfo cellInfo = PoolManager.Inst.Get<CellInfo>();
cellInfo.index = i;
cellInfoList.Add(cellInfo);
}
Vector2 cellSize = cellPrefab.GetSize();
switch (scrollDirection)
{
case ScrollDirection.TopToDown:
case ScrollDirection.DownToTop:
int rowNum = dataMaxNum / rowOrColNum + 1;
float width = (cellSize.x + specing.x) * rowOrColNum - specing.x;
float height = (cellSize.y + specing.y) * rowNum - specing.y;
content.gameObject.SetSize(new Vector2(width, height));
for (int i = 0; i < cellInfoList.Count; i++)
{
CellInfo cellInfo = cellInfoList[i];
int curCol = i % rowOrColNum;
int curRow = i / rowOrColNum;
float posX = curCol * (cellSize.x + specing.x);
float posY = -curRow * (cellSize.y + specing.y);
cellInfo.pos = new Vector3(posX, posY);
//Debug.Log(cellInfo.pos);
}
break;
case ScrollDirection.LeftToRight:
case ScrollDirection.RightToLeft:
int colNum = dataMaxNum / rowOrColNum + 1;
float contentWidth = (cellSize.x + specing.x) * colNum - specing.x;
float contentHeight = (cellSize.y + specing.y) * rowOrColNum - specing.y;
content.gameObject.SetSize(new Vector2(contentWidth, contentHeight));
for (int i = 0; i < cellInfoList.Count; i++)
{
CellInfo cellInfo = cellInfoList[i];
int curRow = i % rowOrColNum;
int curCol = i / rowOrColNum;
float posX = curCol * (cellSize.x + specing.x);
float posY = -curRow * (cellSize.y + specing.y);
cellInfo.pos = new Vector3(posX, posY);
//Debug.Log(cellInfo.pos);
}
break;
default:
break;
}
CheckCellItemData();
}
Vector2 lastPos = Vector2.zero;
Vector2 curPos = Vector2.zero;
private void ScrollOnDragListener(Vector2 pos)
{
curPos = pos;
if (curPos != lastPos)
{
//Debug.Log(pos);
CheckCellItemData();
}
lastPos = curPos;
}
private void CheckCellItemData()
{
for (int i = 0; i < cellInfoList.Count; i++)
{
CellInfo cellInfo = cellInfoList[i];
//Debug.Log(cellInfo.pos);
if (IsInScrollRange(cellInfo))
{
if (cellInfo.item == null)
{
cellInfo.item = PoolManager.Inst.Get(cellPrefab, content);
cellInfo.item.transform.localPosition = cellInfo.pos;
cellInfo.item.name = cellInfo.index.ToString();
}
actionEvent?.Invoke(cellInfo.item, cellInfo.index);
}
else
{
if (cellInfo.item != null)
{
cellInfo.item.PushPool(cellPrefab.name);
cellInfo.item = null;
}
}
}
}
private bool IsInScrollRange(CellInfo cellInfo)
{
Vector2 contentPos = content.anchoredPosition;
Vector2 scrollSize = scrollRect.gameObject.GetSize();
Vector2 cellSize = cellPrefab.GetSize();
float topPos = -contentPos.y + cellSize.y;
float downPos = -contentPos.y - scrollSize.y;
float leftPos = -contentPos.x - cellSize.x;
float rightPos = -contentPos.x + scrollSize.x;
//Debug.Log($"cellInfo.pos:{cellInfo.pos} topPos:{topPos}/downPos:{downPos}/leftPos:{leftPos}/rightPos:{rightPos}");
if (cellInfo.pos.x >= leftPos && cellInfo.pos.x <= rightPos && cellInfo.pos.y >= downPos && cellInfo.pos.y <= topPos)
{
return true;
}
return false;
}
#if UNITY_EDITOR
2024-10-31 10:58:14 +08:00
[MenuItem("GameObject/UIEx/ScrollViewEx/ScrollViewGridEx", priority = -990)]
2024-10-11 10:12:15 +08:00
private static void CreateScrollViewEx(MenuCommand menuCmd)
{
GameObject selection = Selection.activeGameObject;
2024-10-31 10:58:14 +08:00
CommonExtension.CreateComponent<ScrollRect>(selection, (obj) =>
2024-10-11 10:12:15 +08:00
{
2024-10-31 10:58:14 +08:00
obj.SetWidth(800);
obj.SetHeight(600);
GameObject viewport = ObjectFactory.CreateGameObject("Viewport", typeof(Image), typeof(Mask));
viewport.transform.SetParent(obj.transform, false);
RectTransform viewportRect = viewport.GetComponent<RectTransform>();
viewportRect.anchorMin = new Vector2(0, 0);
viewportRect.anchorMax = new Vector2(1, 1);
viewportRect.pivot = new Vector2(0, 1);
viewport.SetWidth(0);
viewport.SetHeight(0);
Mask viewportMask = viewport.GetComponent<Mask>();
viewportMask.showMaskGraphic = false;
GameObject content = ObjectFactory.CreateGameObject("Content", typeof(RectTransform));
content.transform.SetParent(viewport.transform, false);
RectTransform contentRect = content.GetComponent<RectTransform>();
contentRect.anchorMin = new Vector2(0, 1);
contentRect.anchorMax = new Vector2(0, 1);
contentRect.pivot = new Vector2(0, 1);
content.SetWidth(800);
content.SetHeight(600);
ScrollRect scrollRect = obj.GetComponent<ScrollRect>();
scrollRect.content = contentRect;
scrollRect.viewport = viewportRect;
scrollRect.horizontal = false;
scrollRect.vertical = true;
ScrollViewGridEx scrollViewEx = obj.GetComponent<ScrollViewGridEx>();
scrollViewEx.content = contentRect;
}, typeof(Canvas));
2024-10-11 10:12:15 +08:00
}
#endif
}
}