UGUI—UIListView
作者:追风剑情 发布于:2019-11-4 17:56 分类:Unity3d
一、工程截图
二、代码实现
UIListView.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
/// <summary>
/// 自定义UIList
/// </summary>
public class UIListView : UIBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public RectTransform root;
public RectTransform itemTemplet;
public Rect rect;
public int count;
public float space; //间隔距离
public float itemHeight;
public float KickBackSpeed = 1;
public float MoveSpeed = 1;
private List<RectTransform> list;
public delegate bool OnFillDataCallback(int index, GameObject go);
public OnFillDataCallback OnFillData;
private RectTransform m_RectTransform;
private MoveDirection m_MoveDirection;
private MoveState m_MoveState;
private float m_TotalHeight;
private float m_LastDragTime = 0;
private Vector2 m_LastDragPosition;
private float m_MoveY;
private float t;
public RectTransform rectTransform
{
get
{
if (ReferenceEquals(m_RectTransform, null))
{
m_RectTransform = GetComponent<RectTransform>();
}
return m_RectTransform;
}
}
protected override void Start()
{
itemTemplet.gameObject.SetActive(false);
float y = 0;
for (int i=0; i<count; i++)
{
y = -(itemHeight + space) * i;
RectTransform tran = CreateItem();
SetPosition(tran, 0, y);
//通过回调方法给选项设值
if (OnFillData != null)
OnFillData(i, tran.gameObject);
}
m_TotalHeight = Mathf.Abs(y) + itemHeight;
RectMask2D mask = this.gameObject.AddComponent<RectMask2D>();
mask.PerformClipping();
}
private void Update()
{
if (m_MoveState == MoveState.KickBack)
{
t += Time.deltaTime * KickBackSpeed;
if (PositionY < 0)
PositionY = Mathf.SmoothStep(PositionY, 0, t);
else if (PositionY > MinPositionY)
PositionY = Mathf.SmoothStep(PositionY, MinPositionY, t);
else
m_MoveState = MoveState.Static;
}
else if (m_MoveState == MoveState.Moving)
{
t += Time.deltaTime * MoveSpeed;
MoveSpeed /= 2;
Debug.Log(MoveSpeed);
PositionY = Mathf.SmoothStep(PositionY, m_MoveY, t);
if (t >= 1 || MoveSpeed <= 0)
m_MoveState = MoveState.Static;
}
}
public void OnBeginDrag(PointerEventData eventData)
{
m_MoveState = MoveState.Static;
}
public void OnDrag(PointerEventData eventData)
{
Vector2 delta = eventData.delta;
SetDeltaPosition(root, 0, delta.y);
m_MoveDirection = delta.y > 0 ? MoveDirection.Up : MoveDirection.Down;
m_MoveState = MoveState.Dragging;
m_LastDragTime = Time.time;
m_LastDragPosition = eventData.position;
}
public void OnEndDrag(PointerEventData eventData)
{
t = 0;
m_MoveState = PositionY > MinPositionY || PositionY < 0 ? MoveState.KickBack : MoveState.Static;
if (PositionY > MinPositionY || PositionY < 0)
{
m_MoveState = MoveState.KickBack;
}
else
{
if (Time.time - m_LastDragTime < 0.5f)
{
float time = Time.time - m_LastDragTime;
float s = eventData.position.y - m_LastDragPosition.y;
MoveSpeed = Mathf.Abs(s) / time / 1000;
if (Mathf.Abs(s) > 1)
{
m_MoveY = PositionY + s * 5000;
if (m_MoveY < 0)
m_MoveY = 0;
else if (m_MoveY > MinPositionY)
m_MoveY = MinPositionY;
m_MoveState = MoveState.Moving;
t = 0;
}
else
{
m_MoveState = MoveState.Static;
}
}
else
{
m_MoveState = MoveState.Static;
}
}
}
private RectTransform CreateItem()
{
RectTransform tran = GameObject.Instantiate<RectTransform>(itemTemplet);
tran.SetParent(root);
tran.gameObject.SetActive(true);
return tran;
}
private void SetPosition(RectTransform tran, float x, float y)
{
tran.anchoredPosition = new Vector2(x, y);
}
private void SetDeltaPosition(RectTransform tran, float deltaX, float deltaY)
{
Vector2 pos = tran.anchoredPosition;
pos.x += deltaX;
pos.y += deltaY;
tran.anchoredPosition = pos;
}
private float PositionY
{
get
{
return root.anchoredPosition.y;
}
set
{
SetPosition(root, 0, value);
}
}
private float MinPositionY
{
get
{
if (m_TotalHeight <= rect.height)
return 0;
return m_TotalHeight - rect.height;
}
}
private float BottomPositionY
{
get
{
return m_TotalHeight;
}
}
private enum MoveDirection
{
None,
Up,
Down
}
private enum MoveState
{
Static, //静止
Dragging, //拖拽
Moving, //移动
KickBack, //回弹
}
}
UIListItem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
/// <summary>
/// 列表选项
/// </summary>
public class UIListItem : MonoBehaviour, IPointerClickHandler
{
public Text text;
public void SetText(string s)
{
this.text.text = s;
}
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Click: " + text.text);
}
}
UIListViewTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 测试
/// </summary>
public class UIListViewTest : MonoBehaviour
{
void Awake()
{
UIListView listView = this.GetComponent<UIListView>();
listView.OnFillData = new UIListView.OnFillDataCallback(OnFillData);
}
private bool OnFillData(int index, GameObject go)
{
Debug.LogFormat("OnFillData({0}, go)", index, go);
UIListItem item = go.GetComponent<UIListItem>();
item.SetText("Number " + index);
return true;
}
}
三、运行效果
第二版:支持无限循环、支持多行多列布局、支持左右或上下滑动
工程截图
UIListView.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
/// <summary>
/// 无限循环列表
/// </summary>
public class UIListView : MonoBehaviour
{
[SerializeField]
private int m_Count = 0;
private RectTransform m_RectTransform;
private Rect m_ListRect;
private UIListViewLayout m_Layout;
private UIListViewDragHandler m_DragHandler;
private bool m_started;
//判断列表是否已初始化完成
public bool initialized
{
get
{
return m_started;
}
}
public RectTransform rectTransform
{
get {
if (m_RectTransform == null)
m_RectTransform = this.GetComponent<RectTransform>();
return m_RectTransform;
}
}
public Rect Rect { get { return rectTransform.rect; } }
//数据个数
public int Count { get { return m_Count; } set { m_Count = value; } }
//列表宽度
public float Width { get { return m_ListRect.width; } }
//列表高度
public float Height { get { return m_ListRect.height; } }
private void Awake()
{
if (m_RectTransform == null)
m_RectTransform = this.GetComponent<RectTransform>();
m_ListRect = m_RectTransform.rect;
Transform content = transform.Find("Viewport/Content");
m_Layout = content.GetComponent<UIListViewLayout>();
m_DragHandler = content.GetComponent<UIListViewDragHandler>();
}
private void Start()
{
m_started = true;
//再次获取,确保获取正确值
m_ListRect = m_RectTransform.rect;
}
//重置滑动 (会让列表坐标回到起始位置,并刷新数据)
public void ResetScroll()
{
if (!initialized)
{
Debug.LogWarning("ListView initialization is not complete, Cannot call ResetScroll().");
return;
}
m_DragHandler.ResetScroll();
m_Layout.ResetLayout();
}
//刷新数据 (不影响列表坐标)
public void Refresh()
{
if (!initialized)
{
Debug.LogWarning("ListView initialization is not complete, Cannot call Refresh().");
return;
}
m_Layout.Refresh();
}
}
IListViewItem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 所有自定义的Item都要实现这个接口
/// </summary>
public interface IListViewItem
{
int Index { get; set; }
bool OnFillData(int index);
GameObject gameObject { get; }
}
UIListViewLayout.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 控制列表布局
/// </summary>
public class UIListViewLayout : MonoBehaviour
{
public enum LayoutDirection
{
Horizontal,
Vertical
}
[SerializeField]
private LayoutDirection m_direction = LayoutDirection.Vertical;
public LayoutDirection layoutDirection { get { return m_direction; } }
[SerializeField]
private int m_RowCount = 1;
[SerializeField]
private int m_ColumnCount = 1;
[SerializeField]
private float m_RowSpace = 10;
[SerializeField]
private float m_ColumnSpace = 10;
private UIListView m_ListView;
private GameObject m_ItemTemplet;
private Rect m_ListRect;
private Rect m_ItemRect;
private int m_InitCount = 0;
private List<RectTransform> m_ItemList = new List<RectTransform>();
private RectTransform m_RectTransform;
public RectTransform rectTransform
{
get
{
if (m_RectTransform == null)
m_RectTransform = this.GetComponent<RectTransform>();
return m_RectTransform;
}
}
public float Width
{
get
{
return rectTransform.rect.width;
}
set
{
Vector2 sizeDelta = rectTransform.sizeDelta;
sizeDelta.x = value;
rectTransform.sizeDelta = sizeDelta;
}
}
public float Height
{
get
{
return rectTransform.rect.height;
}
set
{
Vector2 sizeDelta = rectTransform.sizeDelta;
sizeDelta.y = value;
rectTransform.sizeDelta = sizeDelta;
}
}
private void Awake()
{
m_ListView = this.GetComponentInParent<UIListView>();
Transform itemTemplet = transform.Find("ItemTemplet");
if (itemTemplet != null)
{
m_ItemTemplet = itemTemplet.gameObject;
m_ItemRect = m_ItemTemplet.GetComponent<RectTransform>().rect;
}
else
Debug.LogErrorFormat("Not found ItemTemplet by Find(\"ItemTemplet\")");
}
private void Start()
{
m_ListRect = m_ListView.Rect;
CalculateContentSize();
InitItemList();
}
private void InitItemList()
{
//自动计算要初始生成多少个Item项
if (m_direction == LayoutDirection.Vertical)
{
m_InitCount = Mathf.CeilToInt(m_ListRect.height / (m_ItemRect.height + m_RowSpace)) + 1;
m_InitCount *= m_ColumnCount;
}
else
{
m_InitCount = Mathf.CeilToInt(m_ListRect.width / (m_ItemRect.width + m_ColumnSpace)) + 1;
m_InitCount *= m_RowCount;
}
for (int i = 0; i < m_InitCount; i++)
{
GameObject go = CloneTemplet();
IListViewItem item = go.GetComponent<IListViewItem>();
item.Index = i;
bool result = item.OnFillData(i);
go.SetActive(result);
}
m_ItemTemplet.SetActive(false);
UpdateLayout();
}
private GameObject CloneTemplet()
{
GameObject go = Instantiate(m_ItemTemplet);
go.transform.SetParent(transform);
go.transform.localScale = Vector3.one;
go.transform.localPosition = Vector3.zero;
m_ItemList.Add(go.GetComponent<RectTransform>());
return go;
}
//计算内容区尺寸
private void CalculateContentSize()
{
if (m_direction == LayoutDirection.Vertical)
{
int rowCount = m_ListView.Count / m_ColumnCount;
if (m_ListView.Count % m_ColumnCount != 0)
rowCount++;
Width = m_ColumnCount * (m_ItemRect.width + m_ColumnSpace);
float h = rowCount * (m_ItemRect.height + m_RowSpace);
Height = Mathf.Max(h, m_ListView.Height);
}
else
{
int columnCount = m_ListView.Count / m_RowCount;
if (m_ListView.Count % m_RowCount != 0)
columnCount++;
float w = columnCount * (m_ItemRect.width + m_ColumnSpace);
Width = Mathf.Max(w, m_ListView.Width);
Height = m_RowCount * (m_ItemRect.height + m_RowSpace);
}
}
public void UpdateLayout()
{
for (int i = 0; i < m_ItemList.Count; i++)
{
IListViewItem item = m_ItemList[i].GetComponent<IListViewItem>();
Vector3 pos = IndexToPosition(item.Index);
m_ItemList[i].localPosition = pos;
}
}
//将Content中的坐标转到Viewport坐标系中
private Vector3 ContentToViewportPosition(Vector3 pos)
{
pos.x = rectTransform.anchoredPosition.x + pos.x;
pos.y = rectTransform.anchoredPosition.y + pos.y;
return pos;
}
//判断坐标是否在Viewport中
private bool ContainViewportPosition(Vector3 pos)
{
bool inX = pos.x >= 0 && pos.x <= m_ListView.Width;
bool inY = pos.y >= -m_ListView.Height && pos.y <= 0;
return inX && inY;
}
//判断坐标是否在有效Content区中
private bool ContainContentRangePosition(Vector3 pos)
{
bool inX = pos.x >= 0 && pos.x <= Width;
bool inY = pos.y >= -Height && pos.y <= 0;
return inX && inY;
}
//坐标转Index
public int PositionToIndex(Vector3 pos)
{
int index = 0;
float offsetY = (m_ItemRect.height + m_RowSpace) / 2;
float offsetX = (m_ItemRect.width + m_ColumnSpace) / 2;
float rowHeight = m_ItemRect.height + m_RowSpace;
float columnWidth = m_ItemRect.width + m_ColumnSpace;
int row = (int)((Mathf.Abs(pos.y) + offsetY) / rowHeight);
int column = (int)((Mathf.Abs(pos.x) + offsetX) / columnWidth);
if (m_direction == LayoutDirection.Vertical)
index = row * m_ColumnCount + column + 1;
else
index = column * m_RowCount + row + 1;
return index;
}
//Index转坐标
public Vector3 IndexToPosition(int index)
{
Vector3 pos = Vector3.zero;
int row, column;
if (m_direction == LayoutDirection.Vertical)
{
row = index / m_ColumnCount;
column = index % m_ColumnCount;
}
else
{
row = index % m_RowCount;
column = index / m_RowCount;
}
float x = column * (m_ItemRect.width + m_ColumnSpace);
float y = row * (m_ItemRect.height + m_RowSpace);
pos.x = x;
pos.y = -y;
return pos;
}
//后移Item
public void BackItem()
{
RectTransform firstTran = m_ItemList[0];
RectTransform lastTran = m_ItemList[m_ItemList.Count - 1];
Vector3 firstPos = firstTran.localPosition;
Vector3 lastPos = lastTran.localPosition;
//如果lastItem的左上角还在可视区内可见,则直接返回
Vector3 ipos = lastPos;
ipos = ContentToViewportPosition(ipos);
if (ContainViewportPosition(ipos))
return;
//如果lastItem的右下角还在可视区内可见,则直接返回
ipos.x += lastTran.rect.width;
ipos.y -= lastTran.rect.height;
if (ContainViewportPosition(ipos))
return;
IListViewItem firstItem = firstTran.GetComponent<IListViewItem>();
int index = firstItem.Index - 1;
//数据越界
if (index < 0)
return;
m_ItemList.RemoveAt(m_ItemList.Count - 1);
m_ItemList.Insert(0, lastTran);
lastTran.localPosition = IndexToPosition(index);
//填充数据
IListViewItem lastItem = lastTran.GetComponent<IListViewItem>();
lastItem.Index = index;
bool result = lastItem.OnFillData(index);
lastTran.gameObject.SetActive(result);
}
//前移Item
public void ForwardItem()
{
RectTransform firstTran = m_ItemList[0];
RectTransform lastTran = m_ItemList[m_ItemList.Count - 1];
Vector3 firstPos = firstTran.localPosition;
Vector3 lastPos = lastTran.localPosition;
//如果firstItem的左上角还在可视区内可见,则直接返回
Vector3 ipos = firstPos;
ipos = ContentToViewportPosition(ipos);
if (ContainViewportPosition(ipos))
return;
//如果firstItem的右下角还在可视区内可见,则直接返回
//以下算法基于item的Pivot为左上角(0,1)
ipos.x += firstTran.rect.width;
ipos.y -= firstTran.rect.height;
if (ContainViewportPosition(ipos))
return;
IListViewItem lastItem = lastTran.GetComponent<IListViewItem>();
int index = lastItem.Index + 1;
//数据越界检查
if (m_direction == LayoutDirection.Vertical)
{
//确保整行往前移动
bool isFirstColumn = (index % m_ColumnCount == 0);
if (index >= m_ListView.Count && isFirstColumn)
return;
}
else
{
//确保整列往前移动
bool isFirstRow = (index % m_RowCount == 0);
if (index >= m_ListView.Count && isFirstRow)
return;
}
m_ItemList.RemoveAt(0);
m_ItemList.Add(firstTran);
firstTran.localPosition = IndexToPosition(index);
//填充数据
IListViewItem firstItem = firstTran.GetComponent<IListViewItem>();
firstItem.Index = index;
bool result = firstItem.OnFillData(index);
firstTran.gameObject.SetActive(result);
}
//重置布局
public void ResetLayout()
{
for (int i = 0; i < m_ItemList.Count; i++)
{
IListViewItem item = m_ItemList[i].GetComponent<IListViewItem>();
item.Index = i;
bool active = item.OnFillData(item.Index);
item.gameObject.SetActive(active);
item.gameObject.transform.localPosition = IndexToPosition(item.Index);
}
CalculateContentSize();
}
//刷新数据
public void Refresh()
{
var firstItem = m_ItemList[0].GetComponent<IListViewItem>();
int index = firstItem.Index;
for (int i = 0; i < m_ItemList.Count; i++)
{
IListViewItem item = m_ItemList[i].GetComponent<IListViewItem>();
bool active = item.OnFillData(index++);
item.gameObject.SetActive(active);
}
CalculateContentSize();
}
}
UIListViewDragHandler.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
/// <summary>
/// 挂在Content上
/// </summary>
public class UIListViewDragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerDownHandler
{
public float MoveSpeed = 1;
private RectTransform m_RectTransform;
private MoveDirection m_MoveDirection;
private MoveState m_MoveState;
private float m_LastDragTime;
private Vector2 m_LastDragPosition;
private float t;
private float m_MoveY;
private float m_MoveX;
private UIListView m_UIListView;
private UIListViewLayout m_Layout;
private Rect m_ListRect;
private const float MAX_SPEED = 1f;
[Serializable]
public class OnScrollEndEvent : UnityEvent { }
// 防止序列化变量重命名后丢失引用
[FormerlySerializedAs("onScrollEnd")]
[SerializeField]
private OnScrollEndEvent m_OnScrollEnd = new OnScrollEndEvent();
private enum MoveDirection
{
None,
Up,
Down,
Left,
Right
}
private enum MoveState
{
Static, //静止
Dragging, //拖拽
Moving, //移动
KickBack, //回弹
}
private void Start()
{
m_RectTransform = this.GetComponent<RectTransform>();
m_Layout = this.GetComponent<UIListViewLayout>();
m_UIListView = transform.GetComponentInParent<UIListView>();
m_ListRect = m_UIListView.Rect;
}
private void Update()
{
switch (m_MoveState)
{
case MoveState.Moving:
t += Time.deltaTime * MoveSpeed;
MoveSpeed /= 2;
switch (m_Layout.layoutDirection)
{
case UIListViewLayout.LayoutDirection.Vertical:
PositionY = Mathf.SmoothStep(PositionY, m_MoveY, t);
break;
case UIListViewLayout.LayoutDirection.Horizontal:
PositionX = Mathf.SmoothStep(PositionX, m_MoveX, t);
break;
}
if (t >= 1 || MoveSpeed <= 0)
m_MoveState = MoveState.Static;
switch (m_MoveDirection)
{
case MoveDirection.Up:
case MoveDirection.Left:
m_Layout.ForwardItem();
break;
case MoveDirection.Down:
case MoveDirection.Right:
m_Layout.BackItem();
break;
}
break;
case MoveState.KickBack:
t += Time.deltaTime * MoveSpeed;
switch (m_Layout.layoutDirection)
{
case UIListViewLayout.LayoutDirection.Vertical:
m_MoveDirection = PositionY > m_MoveY ? MoveDirection.Down : MoveDirection.Up;
PositionY = Mathf.SmoothStep(PositionY, m_MoveY, t);
break;
case UIListViewLayout.LayoutDirection.Horizontal:
m_MoveDirection = PositionY > m_MoveY ? MoveDirection.Right : MoveDirection.Left;
PositionX = Mathf.SmoothStep(PositionX, m_MoveX, t);
break;
}
if (t >= 1)
m_MoveState = MoveState.Static;
switch (m_MoveDirection)
{
case MoveDirection.Up:
case MoveDirection.Left:
m_Layout.ForwardItem();
break;
case MoveDirection.Down:
case MoveDirection.Right:
m_Layout.BackItem();
break;
}
break;
}
}
public void OnPointerDown(PointerEventData eventData)
{
if (m_MoveState == MoveState.Moving)
m_MoveState = MoveState.Static;
}
public void OnBeginDrag(PointerEventData eventData)
{
m_MoveState = MoveState.Static;
}
public void OnDrag(PointerEventData eventData)
{
m_MoveState = MoveState.Dragging;
m_LastDragTime = Time.time;
m_LastDragPosition = eventData.position;
Vector2 delta = eventData.delta;
switch (m_Layout.layoutDirection)
{
case UIListViewLayout.LayoutDirection.Vertical:
m_MoveDirection = delta.y > 0 ? MoveDirection.Up : MoveDirection.Down;
SetDeltaPositionY(delta.y);
break;
case UIListViewLayout.LayoutDirection.Horizontal:
m_MoveDirection = delta.x > 0 ? MoveDirection.Right : MoveDirection.Left;
SetDeltaPositionX(delta.x);
break;
}
switch (m_MoveDirection)
{
case MoveDirection.Up:
case MoveDirection.Left:
m_Layout.ForwardItem();
break;
case MoveDirection.Down:
case MoveDirection.Right:
m_Layout.BackItem();
break;
}
}
public void OnEndDrag(PointerEventData eventData)
{
t = 0;
CheckKickBack();
if (m_MoveState == MoveState.KickBack)
return;
switch (m_Layout.layoutDirection)
{
case UIListViewLayout.LayoutDirection.Vertical:
if (Time.time - m_LastDragTime < 0.5f)
{
float time = Time.time - m_LastDragTime;
float s = eventData.position.y - m_LastDragPosition.y;
MoveSpeed = Mathf.Abs(s) / time / 5000;
MoveSpeed = Mathf.Clamp(MoveSpeed, 0, MAX_SPEED);
if (Mathf.Abs(s) > 1)
{
m_MoveY = PositionY + s * 5000;
if (m_MoveY < MinPositionY)
m_MoveY = MinPositionY;
else if (m_MoveY > MaxPositionY)
m_MoveY = MaxPositionY;
m_MoveState = MoveState.Moving;
}
else
{
m_MoveState = MoveState.Static;
}
}
else
{
m_MoveState = MoveState.Static;
}
break;
case UIListViewLayout.LayoutDirection.Horizontal:
if (Time.time - m_LastDragTime < 0.5f)
{
float time = Time.time - m_LastDragTime;
float s = eventData.position.x - m_LastDragPosition.x;
MoveSpeed = Mathf.Abs(s) / time / 5000;
MoveSpeed = Mathf.Clamp(MoveSpeed, 0, MAX_SPEED);
if (Mathf.Abs(s) > 1)
{
m_MoveX = PositionX + s * 5000;
if (m_MoveX < MinPositionX)
m_MoveX = MinPositionX;
else if (m_MoveX > MaxPositionX)
m_MoveX = MaxPositionX;
m_MoveState = MoveState.Moving;
}
else
{
m_MoveState = MoveState.Static;
}
}
else
{
m_MoveState = MoveState.Static;
}
break;
}
}
//检测是否进入回弹状态
private void CheckKickBack()
{
switch (m_Layout.layoutDirection)
{
case UIListViewLayout.LayoutDirection.Vertical:
if (PositionY < MinPositionY || PositionY > MaxPositionY)
{
m_MoveState = MoveState.KickBack;
MoveSpeed = 2;
m_MoveY = Mathf.Clamp(PositionY, MinPositionY, MaxPositionY);
}
if (PositionY >= MaxPositionY)
m_OnScrollEnd.Invoke();
break;
case UIListViewLayout.LayoutDirection.Horizontal:
if (PositionX < MinPositionX || PositionX > MaxPositionX)
{
m_MoveState = MoveState.KickBack;
MoveSpeed = 2;
m_MoveX = Mathf.Clamp(PositionX, MinPositionX, MaxPositionX);
}
if (PositionX <= MinPositionX)
m_OnScrollEnd.Invoke();
break;
}
}
private void SetDeltaPosition(float deltaX, float deltaY)
{
Vector2 pos = m_RectTransform.anchoredPosition;
pos.x += deltaX;
pos.y += deltaY;
m_RectTransform.anchoredPosition = pos;
}
private void SetDeltaPositionX(float deltaX)
{
Vector2 pos = m_RectTransform.anchoredPosition;
pos.x += deltaX;
m_RectTransform.anchoredPosition = pos;
}
private void SetDeltaPositionY(float deltaY)
{
Vector2 pos = m_RectTransform.anchoredPosition;
pos.y += deltaY;
m_RectTransform.anchoredPosition = pos;
}
private void SetPosition(float x, float y)
{
Vector2 pos = m_RectTransform.anchoredPosition;
pos.x = x;
pos.y = y;
m_RectTransform.anchoredPosition = pos;
}
private float PositionX
{
get {
return m_RectTransform.anchoredPosition.x;
}
set {
SetPosition(value, m_RectTransform.anchoredPosition.y);
}
}
private float PositionY
{
get {
return m_RectTransform.anchoredPosition.y;
}
set {
SetPosition(m_RectTransform.anchoredPosition.x, value);
}
}
private float MinPositionX
{
get { return m_UIListView.Width - m_Layout.Width; }
}
private float MaxPositionX
{
get { return 0; }
}
private float MinPositionY
{
get { return 0; }
}
private float MaxPositionY
{
get { return m_Layout.Height - m_UIListView.Height; }
}
//重置滑动
public void ResetScroll()
{
m_MoveState = MoveState.Static;
SetPosition(0, 0);
}
}
SimpleListViewItem.cs
using UnityEngine.EventSystems;
// 简单实现 IListViewItem
public class SimpleListViewItem : GameEventBehaviour, IListViewItem, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler
{
public virtual int Index { get; set; }
public virtual bool OnFillData(int index)
{
return true;
}
public void OnPointerDown(PointerEventData eventData)
{
OnPointerDown();
}
public void OnPointerUp(PointerEventData eventData)
{
OnPointerUp();
}
public void OnPointerClick(PointerEventData eventData)
{
OnPointerClick();
}
public virtual void OnPointerDown() { }
public virtual void OnPointerUp() { }
public virtual void OnPointerClick() { }
}
CustomListItem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 自定义Item类
/// </summary>
public class CustomListItem : MonoBehaviour, IListViewItem
{
[SerializeField]
private Text m_Text;
public int Index { get; set; }
public bool OnFillData(int index)
{
m_Text.text = string.Format("Item {0}", index);
return true;
}
public void OnClick()
{
Debug.Log(m_Text.text);
}
}
标签: Unity3d
日历
最新文章
随机文章
热门文章
分类
存档
- 2025年11月(1)
- 2025年9月(3)
- 2025年7月(4)
- 2025年6月(5)
- 2025年5月(1)
- 2025年4月(5)
- 2025年3月(4)
- 2025年2月(3)
- 2025年1月(1)
- 2024年12月(5)
- 2024年11月(5)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
- Open CASCADE
- CascadeStudio
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号


















