using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using System.Diagnostics;
namespace ymr
{
public enum ViewDirection
{
Vertical,//纵向滑动(为主)
Horizontal,//横向滑动
}
public class TableView : MonoBehaviour, IPointerDownHandler
{
public GameObject m_pCell;//cell的引用(横向的cell)
//1.ui data
private Dictionary m_dCells;// 可见子项集合
private List m_vReUseCells;// 可重用子项集合
private ViewDirection m_CurrentDirection;// 当前滑动方向
private Vector2 m_TotalContentSize;//总内容的size大小
private Vector2 m_VisibleViewSize;//可见区域的size大小
private Vector2 m_CellSize;//子项size大小(目前只针对固定大小的size的tableview)
private float m_fTotalScrollDistance;// 可滑动距离
private Vector2 m_ContentOffset;// 已滑动距离
private bool m_bIsContentThanVisibleView = true;// 内容面板尺寸是否大于可见面板
private int m_iLineCount;
//2.UI
private ScrollRect m_pScrollRect;// ScrollRect组件
private RectTransform m_pRectTransform;// RectTransform组件
private RectTransform m_pContentTransform;// 内容面板RectTransform组件
//3.date
private List m_vTexts;//模拟数据
//-----------------------------------------------------------------------------------
private void InitComponent()
{
// 初始化组件
m_pScrollRect = this.GetComponent();
m_pRectTransform = this.GetComponent();
m_pContentTransform = m_pScrollRect.content;
Trace.Assert(m_pCell != null, "m_pCell is null");
Trace.Assert(m_pScrollRect != null, "m_pScrollRect is null");
Trace.Assert(m_pRectTransform != null, "m_pRectTransform is null");
Trace.Assert(m_pContentTransform != null, "m_pContentTransform is null");
}
private void InitUIData()
{
// 初始化变量
m_dCells = new Dictionary();
m_vReUseCells = new List();
//这里不处理横纵向都能滑动的结果
if (m_pScrollRect.vertical == true)//根据ScrollRect组件属性设置滑动方向
{
m_CurrentDirection = ViewDirection.Vertical;
m_pContentTransform.anchorMin = new Vector2(0.5f, 1f);
m_pContentTransform.anchorMax = new Vector2(0.5f, 1f);
m_pContentTransform.pivot = new Vector2(0.5f, 1f);
}
else
{
m_CurrentDirection = ViewDirection.Horizontal;
m_pContentTransform.anchorMin = new Vector2(0f, 0.5f);
m_pContentTransform.anchorMax = new Vector2(0f, 0.5f);
m_pContentTransform.pivot = new Vector2(0f, 0.5f);
}
m_VisibleViewSize = m_pRectTransform.sizeDelta;
m_CellSize = m_pCell.GetComponent().sizeDelta;
m_iLineCount = NumberOfLineCount();
}
private void InitView()
{
// 初始化面板
Vector2 contentSize = m_pContentTransform.sizeDelta;
int iCellTotalCount = NumberOfCellsInTableView();
if (m_CurrentDirection == ViewDirection.Vertical)//设置内容面板锚点,对齐方式,纵向滑动为向上对齐
{
m_TotalContentSize = m_CellSize * iCellTotalCount;
m_fTotalScrollDistance = m_TotalContentSize.y - m_VisibleViewSize.y;
contentSize.y = m_TotalContentSize.y;
}
else//设置内容面板锚点,对齐方式,横向滑动为向左对齐
{
m_TotalContentSize = m_CellSize * iCellTotalCount;
m_fTotalScrollDistance = m_TotalContentSize.x - m_VisibleViewSize.x;
contentSize.x = m_TotalContentSize.x;
}
//设置内容面板尺寸
m_pContentTransform.sizeDelta = contentSize;
//设置内容面板坐标
m_pContentTransform.anchoredPosition = Vector2.zero;
//计算需要显示的cell个数
int iShowCellCount = 0;
float fTotalContentLenght = 0f;
float fVisibleViewLenght = 0f;
float fCellLenght = 0f;
if (m_CurrentDirection == ViewDirection.Vertical)
{
fTotalContentLenght = m_TotalContentSize.y;
fVisibleViewLenght = m_VisibleViewSize.y;
fCellLenght = m_CellSize.y;
}
else
{
fTotalContentLenght = m_TotalContentSize.x;
fVisibleViewLenght = m_VisibleViewSize.x;
fCellLenght = m_CellSize.x;
}
if (fVisibleViewLenght > fTotalContentLenght)
{
iShowCellCount = (int)(fTotalContentLenght / fCellLenght);
m_bIsContentThanVisibleView = false;
}
else
{
iShowCellCount = (int)(fVisibleViewLenght / fCellLenght) + 1;
//额外补一个
float tempSize = fVisibleViewLenght + fCellLenght;
float allCellSize = fCellLenght * iShowCellCount;
if (allCellSize < tempSize)
{
iShowCellCount++;
}
}
for (int i = 0; i < iShowCellCount; i++)
{
CreateCellAtIndex(i);
}
}
//-----------------------------------------------------------------------------------
public void CreateCellAtIndex(int index)
{
//创建子项对象
GameObject cell = null;
if (m_vReUseCells.Count > 0)//有可重用子项对象时,复用之
{
cell = m_vReUseCells[0];
m_vReUseCells.RemoveAt(0);
}
else//没有可重用子项对象则创建
{
cell = GameObject.Instantiate(m_pCell) as GameObject;
}
cell.transform.SetParent(m_pContentTransform);
cell.transform.localScale = Vector3.one;
//设置cell基础参数
RectTransform cellRectTrans = cell.GetComponent();
if (m_CurrentDirection == ViewDirection.Vertical)
{
cellRectTrans.anchorMin = new Vector2(0.5f, 1f);
cellRectTrans.anchorMax = new Vector2(0.5f, 1f);
cellRectTrans.pivot = new Vector2(0.5f, 1f);
}
else
{
cellRectTrans.anchorMin = new Vector2(0f, 0.5f);
cellRectTrans.anchorMax = new Vector2(0f, 0.5f);
cellRectTrans.pivot = new Vector2(0f, 0.5f);
}
//设置子项位置
if (m_CurrentDirection == ViewDirection.Vertical)
{
float posY = index * m_CellSize.y;
if (posY > 0)
{
posY = -posY;
}
cellRectTrans.anchoredPosition3D = new Vector3(0, posY, 0);
}
else
{
float posX = index * m_CellSize.x;
cellRectTrans.anchoredPosition3D = new Vector3(posX, 0, 0);
}
TableCellAtIndex(cell, index);
cell.transform.SetAsLastSibling();
m_dCells.Add(index, cell);
}
private void CellScrolling(Vector2 offset)
{
//滑动区域计算
if (!m_bIsContentThanVisibleView)
return;
//offset的x和y都为0~1的浮点数,分别代表横向滑出可见区域的宽度百分比和纵向划出可见区域的高度百分比
m_ContentOffset.x = m_fTotalScrollDistance * offset.x;//滑出可见区域宽度
m_ContentOffset.y = m_fTotalScrollDistance * (1 - offset.y);//滑出可见区域高度
CalCellIndex();
}
private void CalCellIndex()
{
//计算可见区域子项对象开始跟结束下标
float startOffset = 0f;
float endOffset = 0f;
int iStartIndex = 0; //开始下标
int iEndIndex = 0;//结束下标
int iCellTotalCount = NumberOfCellsInTableView();
if (m_CurrentDirection == ViewDirection.Vertical)//纵向滑动
{
startOffset = m_ContentOffset.y;//当前可见区域起始y坐标
endOffset = m_ContentOffset.y + m_VisibleViewSize.y;//当前可见区域结束y坐标
endOffset = endOffset > m_TotalContentSize.y ? m_TotalContentSize.y : endOffset;
iStartIndex = (int)(startOffset / (m_CellSize.y));//子项对象开始下标
iStartIndex = iStartIndex < 0 ? 0 : iStartIndex;
iEndIndex = (int)(endOffset / (m_CellSize.y));//子项对象结束下标
iEndIndex = iEndIndex > (iCellTotalCount - 1) ? (iCellTotalCount - 1) : iEndIndex;
}
else
{
startOffset = m_ContentOffset.x;//当前可见区域起始x坐标
endOffset = m_ContentOffset.x + m_VisibleViewSize.x;//当前可见区域结束y坐标
endOffset = endOffset > m_TotalContentSize.x ? m_TotalContentSize.x : endOffset;
iStartIndex = (int)(startOffset / (m_CellSize.x));//子项对象开始下标
iStartIndex = iStartIndex < 0 ? 0 : iStartIndex;
iEndIndex = (int)(endOffset / (m_CellSize.x));//子项对象结束下标
iEndIndex = iEndIndex > (iCellTotalCount - 1) ? (iCellTotalCount - 1) : iEndIndex;
}
UpdateCells(iStartIndex, iEndIndex);
}
private void UpdateCells(int iStartIndex, int iEndIndex)
{
//管理子项对象集合
List delList = new List();
foreach (KeyValuePair pair in m_dCells)
{
if (pair.Key < iStartIndex || pair.Key > iEndIndex)//回收超出可见范围的子项对象
{
delList.Add(pair.Key);
m_vReUseCells.Add(pair.Value);
}
}
//移除超出可见范围的子项对象
foreach (int index in delList)
{
m_dCells.Remove(index);
}
//根据开始跟结束下标,重新生成子项对象
for (int i = iStartIndex; i <= iEndIndex; i++)
{
if (m_dCells.ContainsKey(i))
{
continue;
}
CreateCellAtIndex(i);
}
}
//-----------------------------------------------------------------------------------
public void OnScrollValueChanged(Vector2 offset)
{
CellScrolling(offset);
}
public void OnPointerDown(PointerEventData eventData)
{
foreach (KeyValuePair pair in m_dCells)
{
List list = new List();
pair.Value.GetComponent().Raycast(eventData, list);
if(list.Count > 0)
{
Vector3 vec = pair.Value.transform.InverseTransformPoint(eventData.position);
print (getIndex(vec));
}
}
}
//-----------------------------------------------------------------------------------
private void Awake()
{
InitComponent();
InitUIData();
syncData();
InitView();
}
private void syncData()
{
//
m_vTexts = new List();
for (int i = 0; i < 19; i++)
{
m_vTexts.Add(i.ToString());
}
}
int NumberOfCellsInTableView()
{
return 10;
}
int NumberOfLineCount()
{
return 2;
}
void TableCellAtIndex(GameObject cell, int idx)
{
if (!cell)
return;
int size = m_vTexts.Count;
for (int i = 0; i < m_iLineCount; ++i)
{
int index = idx * m_iLineCount + i;
Transform tran = cell.transform.Find("Text" + (i + 1).ToString());
if (!tran)
continue;
bool bShow = index < size;
tran.gameObject.SetActive(bShow);
SetCell(tran, index);
}
}
void SetCell(Transform tran, int index)
{
tran.GetComponent().text = "这是第 " + (index + 1) + " 数据";
}
void TableCellTouched()
{
}
int getIndex(Vector3 vec)
{
return (int)((vec.x + m_CellSize.x / 2) / (m_CellSize.x / m_iLineCount));
}
}
}
一.节点的结构图
二.整个参数的重点
三.这里是参考了一些大神的代码完成的,特此鸣谢。如果还有需要的可以留言,我把工程发给大家。