话说那是当年看NGUI的ScrollView,那个迷糊没看懂,后来一直想写个简单的缺迟迟未动手,为啥呢?一脸懵逼
在这时间都不知道丢哪里的时候,硬是海底捞针般的捞起一片片散时,鲁了这个粗糙的ScrollView,忙啥呢?一脸懵逼
扯扯犊子,一天又丢了,丢啥呢?一脸懵逼
。
此处忽略万脸懵逼
。
瞎扯完了,记录点东西,好歹是一直写,很粗糙的简版,有待完善,后续再补个完整版吧
本想备注点啥,看这英语,貌似很中文的样子,就不备注 --。-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
#if UNITY_EDITOR
using UnityEditor;
#endif
public enum EDirection
{
Horizontal,
Vertical,
}
//必要裁切
[RequireComponent(typeof(RectMask2D))]
public class TestScrollView : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
public delegate void DSetElement(Transform ts, int index);
public DSetElement SetElement;
public int Total; //总数
public GameObject template; //模板
public RectOffset Offset; //偏移
public Vector2 ElementSize; //单元格大小
public Vector2 Spacing; //单元格间隔
public EDirection Direction; //方向
public float Smooth = 2.5f; //平滑速度
private Vector2 m_ShowBound; //显示区域
private Transform m_tsContent; //显示父级
private RectTransform m_rtContent; //显示父级
private int m_nCurStartIndex; //当前第一个下标
private int m_nCurEndIndex; //当前最后一个下标
private int m_nColumn; //列数
private int m_nRow; //行数
private int m_ShowTotal;
private Vector2 m_fMax;
private Vector2 m_fMin;
private Vector2 m_v2EndDetal = Vector2.zero;
private bool m_bDraging = false;
private CacahePool m_Pool;
void Awake()
{
if (template == null)
{
Debug.LogError("SrollView 缺少模板");
return;
}
m_Pool = new CacahePool(template);
GameObject goContent = new GameObject();
goContent.name = "content";
goContent.transform.SetParent(transform);
goContent.transform.localRotation = Quaternion.Euler(Vector3.zero);
goContent.transform.localScale = Vector3.one;
//锚点设置
m_rtContent = goContent.AddComponent<RectTransform>();
m_rtContent.anchorMin = new Vector2(0, 1);
m_rtContent.anchorMax = new Vector2(0, 1);
m_rtContent.anchoredPosition = Vector2.zero;
m_tsContent = goContent.transform;
}
public void Initialize()
{
m_ShowBound = new Vector2();
m_ShowBound.x = this.GetComponent<RectTransform>().rect.width;
m_ShowBound.y = this.GetComponent<RectTransform>().rect.height;
m_nColumn = Mathf.FloorToInt((m_ShowBound.x - Offset.left - Offset.right + Spacing.x) / (ElementSize.x + Spacing.x));
m_nRow = Mathf.FloorToInt((m_ShowBound.y - Offset.top - Offset.bottom) / (ElementSize.y + Spacing.y));
m_ShowTotal = Direction == EDirection.Horizontal ? (m_nColumn + 1) * m_nRow : m_nColumn * (m_nRow + 1);
m_fMin = new Vector2(0, 0);
float maxY = 0;
int readyRow = Mathf.CeilToInt((float)Total / m_nColumn);
maxY = readyRow * ElementSize.y + (readyRow - 1) * Spacing.y + Offset.top + Offset.bottom - m_ShowBound.y;
maxY = maxY >= 0 ? maxY : 0;
m_fMax = new Vector2(0, maxY);
UpdatePosition(Vector2.zero);
}
public void OnBeginDrag(PointerEventData data)
{
m_bDraging = true;
}
public void OnDrag(PointerEventData data)
{
Vector2 delta = data.delta;
m_v2EndDetal = delta;
m_v2EndDetal.x = Direction == EDirection.Horizontal ? m_v2EndDetal.x : 0;
m_v2EndDetal.y = Direction == EDirection.Vertical ? m_v2EndDetal.y : 0;
UpdatePosition(m_rtContent.anchoredPosition + m_v2EndDetal);
}
public void OnEndDrag(PointerEventData data)
{
Vector2 delta = data.delta;
m_bDraging = false;
Smooth = Direction == EDirection.Horizontal ? m_v2EndDetal.x : m_v2EndDetal.y;
Smooth = Smooth >= 0 ? Smooth : -Smooth;
Smooth = Smooth * 0.3f;
}
void Update () {
if (m_bDraging || m_rtContent == null) return;
Vector2 pos = m_rtContent.anchoredPosition;
Smooth = Smooth > 5 ? Smooth : 5;
if (Direction == EDirection.Vertical)
{
if (pos.y < m_fMin.y)
{
m_v2EndDetal = Vector2.zero;
if (Vector2.Distance(pos, m_fMin) < 0.1f) return;
UpdatePosition(Vector2.Lerp(pos, m_fMin, Time.deltaTime * Smooth));
return;
}
if (pos.y > m_fMax.y)
{
m_v2EndDetal = Vector2.zero;
if (Vector2.Distance(pos, m_fMax) < 0.1f) return;
UpdatePosition(Vector2.Lerp(pos, m_fMax, Time.deltaTime * Smooth));
return;
}
}
if (m_v2EndDetal == Vector2.zero) return;
m_v2EndDetal = Vector2.Lerp(m_v2EndDetal, Vector2.zero, Time.deltaTime * Smooth);
if (m_v2EndDetal.x < 0.1f && m_v2EndDetal.y < 0.1f && m_v2EndDetal.x > -0.1f && m_v2EndDetal.y > -0.1f)
{
m_v2EndDetal = Vector2.zero;
}
UpdatePosition(m_rtContent.anchoredPosition + m_v2EndDetal);
}
void LateUpdate()
{
int childCount = m_tsContent.childCount;
int firstShowIndex = FirstShowIndex;
int lastShowIndex = LastShowIndex;
for (int i = 0; i < m_UseList.Count; i++)
{
Template tpl = m_UseList[i];
if (tpl.index < firstShowIndex || tpl.index > lastShowIndex)
{
m_Pool.Free(tpl);
m_UseList.RemoveAt(i);
i--;
}
}
}
void UpdatePosition(Vector2 pos)
{
m_rtContent.anchoredPosition = pos;
CheckPosition();
}
Vector3 GetPosByIndex(int index)
{
int row = Mathf.CeilToInt((float)index / m_nColumn);
int column = index - (row - 1) * m_nColumn;
Vector3 pos = new Vector3();
pos.x = Offset.left + column * ElementSize.x + (column - 1) * Spacing.x - ElementSize.x / 2;
pos.y = -(Offset.top + row * ElementSize.y + (row - 1) * Spacing.y - ElementSize.y / 2);
return pos;
}
int FirstShowIndex
{
get
{
int firstShowLine = Mathf.CeilToInt(Mathf.Abs(m_rtContent.anchoredPosition.y - Offset.top) / (ElementSize.y + Spacing.y));
if (m_rtContent.anchoredPosition.y < 0) firstShowLine = 1;
return (firstShowLine - 1) * m_nColumn + 1;
}
}
int LastShowIndex
{
get
{
return FirstShowIndex + m_ShowTotal - 1 + m_nColumn * 2;
}
}
private List<Template> m_UseList = new List<Template>();
void CheckPosition()
{
int curIndex = FirstShowIndex;
for (int i = 1; i <= m_ShowTotal; i++, curIndex++)
{
if (curIndex > Total) return;
Vector3 pos = GetPosByIndex(curIndex);
bool bContinue = false;
for (int j = 0; j < m_UseList.Count; j++)
{
Template tpl = m_UseList[j];
if (tpl.index == curIndex)
{
tpl.ts.localPosition = pos;
bContinue = true;
break;
}
}
if (bContinue) continue;
Template newTpl = m_Pool.Get(curIndex);
newTpl.index = curIndex;
newTpl.ts.name = curIndex.ToString();
newTpl.ts.SetParent(m_tsContent);
newTpl.ts.localRotation = Quaternion.Euler(Vector3.zero);
newTpl.ts.localScale = Vector3.one;
newTpl.ts.localPosition = pos;
newTpl.ts.gameObject.SetActive(true);
m_UseList.Add(newTpl);
if (SetElement != null)
{
SetElement(newTpl.ts, curIndex);
}
SetElementTest(newTpl.ts, curIndex);
}
}
//测试方法
void SetElementTest(Transform ts, int index)
{
if (SetElement != null)
{
SetElement(ts, index);
}
ts.Find("Text").GetComponent<Text>().text = index.ToString();
}
public void Hide()
{
foreach (Template tpl in m_UseList)
{
m_Pool.Free(tpl);
}
m_UseList.Clear();
}
public void Destroy()
{
foreach (Template tpl in m_UseList)
{
GameObject.Destroy(tpl.ts.gameObject);
}
m_UseList.Clear();
m_Pool.Destroy();
}
#if UNITY_EDITOR
void OnGUI()
{
//开始绘制GUI
Handles.BeginGUI();
//规定GUI显示区域
GUILayout.BeginArea(new Rect(0, 0, 100, 100));
if (GUILayout.Button("初始化!"))
{
Initialize();
}
GUILayout.EndArea();
Handles.EndGUI();
}
#endif
//模板
public struct Template
{
public Transform ts;
public int index;
}
//克隆池
private class CacahePool
{
private GameObject m_goTempalte;
private List<Template> m_FreeList;
public CacahePool(GameObject template)
{
m_goTempalte = template;
m_FreeList = new List<Template>();
}
public Template Get(int index)
{
Template tpl;
if (m_goTempalte == null)
{
Debug.LogError("Template is null");
m_goTempalte = new GameObject();
}
if (m_FreeList.Count > 0)
{
int getIndex = 0;
for (int i = 0; i < m_FreeList.Count; i++)
{
if (m_FreeList[i].index == index)
{
getIndex = i;
}
}
tpl = m_FreeList[getIndex];
m_FreeList.RemoveAt(getIndex);
}
else
{
Template newTpl = new Template();
newTpl.ts = GameObject.Instantiate<GameObject>(m_goTempalte).transform;
tpl = newTpl;
}
return tpl;
}
public void Free(Template tpl)
{
tpl.ts.gameObject.SetActive(false);
m_FreeList.Add(tpl);
}
public void Destroy()
{
foreach (Template tpl in m_FreeList)
{
GameObject.Destroy(tpl.ts.gameObject);
}
m_FreeList.Clear();
}
}
}
https://download.csdn.net/download/u014236515/10547690
上面连接是unitypackage文件,现在至少要1积分的样,貌似不能设置0分
版本u3d 2017.3.1 直接导入项目即刻
后续有空再更新,此贴仅做个记录