文章目录
- 前言
- 一、注意事项
- 二、使用步骤
- 1.Item代码
- 2.调用
- 3.InfiniteScrollView脚本
- 总结
前言
在网上找到的大部分要么单行单列的,要么是不能配合Scrollbar使用的,就在其他人的基础上改了一下
提示:以下是本篇文章正文内容,下面案例可供参考
一、注意事项
1.ScrollView里面的Content上的锚点要改一下.
2.GridLayoutGroup里面的StartConer,StartAxixs,ChildAlignment,Constrint会跟代码改变,
3.要用到界面上要有GridLayoutGroup组件
4.ScrollRect里面的Horzontal和Vertical控制是上下拖动还是左右拖动
3.其他的按ScrollView的正常使用方式设置就行了.
二、使用步骤
1.Item代码
拖动的子物体代码,要继承一个GridPartItem脚本,里面有三个虚方法,作为通用方法,被继承
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GridPartItem
{
public GameObject ga;
public virtual void UpdateItem(object itemData)
{
}
public virtual void OnBindItemElements(GameObject ga)
{
this.ga = ga;
}
public virtual void Dispose()
{
}
}
写一个Item类,用来接受动态生成的gameobject,以及一些交互的代码
using UnityEngine;
using UnityEngine.UI;
public class Item : GridPartItem
{
public Text text;
public override void OnBindItemElements(GameObject ga)
{
base.OnBindItemElements(ga);
text = ga.transform.Find("Text").GetComponent<Text>();
}
public override void UpdateItem(object itemData)
{
//text=
ga.name = (string)itemData;
text.text = (string)itemData;
}
}
2.调用
1.在panel上面挂载一个脚本demo,
其中InfiniteScrollView脚本是对ScrollView里面的生成Gameobject进行重新定位,和循环使用的脚本.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class demo : MonoBehaviour
{
public GameObject scrollView;
public GameObject itemPrefab;
// Start is called before the first frame update
void Start()
{
//添加一个数据
List<string> strList = new List<string>() {"name","周亚伟","小灰灰","大灰灰","胖灰灰","瘦灰灰","haha", "周亚伟1" , "小灰灰1" , "大灰灰1" , "胖灰灰1" , "瘦灰灰1" , "haha1" , "周亚伟2" , "小灰灰2" , "大灰灰2" , "胖灰灰2" , "瘦灰灰2" , "haha2" };
//实例化一个InfiniteScrollView
//其中Item类,可以替换为其他item脚本
InfiniteScrollView<Item> item = new InfiniteScrollView<Item>(scrollView , itemPrefab);
List<object> datas = new List<object>();
strList.ForEach(a => datas.Add(a));
//设置item上的数据,数据是一个List,采用通用数据Object格式
item.SetObjectList(datas);
}
// Update is called once per frame
void Update()
{
}
}
3.InfiniteScrollView脚本
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using static UnityEngine.UI.GridLayoutGroup;
/// <summary>
/// 无限滑动列表
/// </summary>
public class InfiniteScrollView<T> where T : GridPartItem,new ()
{
/// <summary>
/// 滑动框组件
/// </summary>
private ScrollRect scrollRect;
/// <summary>
/// 滑动框的Content
/// </summary>
private RectTransform content;
/// <summary>
/// 布局组件
/// </summary>
private GridLayoutGroup layout;//布局组件
/// <summary>
/// 滑动类型
/// </summary>
[Header("滑动类型")]
public ScrollType scrollType;
/// <summary>
/// 生成初始化生成item数量
/// </summary>
private int fixedCount;
[Header("Item的预制体")]
public GameObject itemPrefab;
/// <summary>
/// 总的item数据数量
/// </summary>
private int totalCount;
/// <summary>
/// 数据实体类 RectTransform
/// </summary>
private List<RectTransform> dataList = new List<RectTransform>();
private List<T> itemScriptsList = new List<T>();
private List<object> objectList = new List<object>();
/// <summary>
/// 头下标
/// </summary>
private int headIndex;
/// <summary>
/// 尾下标
/// </summary>
private int tailIndex;
/// <summary>
/// 第一个Item的锚点坐标
/// </summary>
private Vector2 firstItemAnchoredPos;
/// <summary>
/// 获取mask初始宽高
/// </summary>
private Vector2 maskTranV2;
/// <summary>
/// 在mask初始宽高下,一行能放item最多数量,一列放item最多数量
/// </summary>
private int maxItemNumWide, maxItemNumHigh;
#region Init
/// <summary>
/// 实例化Item
/// </summary>
private void InitItem()
{
int num = fixedCount <= totalCount ? fixedCount : totalCount;
for (int i = 0; i < num; i++)
{
GameObject tempItem =GameObject.Instantiate(itemPrefab , content);
dataList.Add(tempItem.GetComponent<RectTransform>());
T itemScript = new T();
itemScript.OnBindItemElements(tempItem);
itemScriptsList.Add(itemScript);
SetShow(itemScript,i);
}
}
/// <summary>
/// 设置Content大小
/// </summary>
private void SetContentSize()
{
if (scrollType == ScrollType.Horizontal)
{
content.sizeDelta = new Vector2
(
layout.padding.left + layout.padding.right + (int)Math.Ceiling((float)totalCount / maxItemNumHigh) * (layoutCellSizeXAndSpacingX) -layout.spacing.x ,
content.rect.height
); ;
}
else if (scrollType == ScrollType.Vertical)
{
content.sizeDelta = new Vector2
(
content.rect.width ,
layout.padding.top + layout.padding.bottom + (int)Math.Ceiling((float)totalCount / maxItemNumWide) * layoutCellSizeYAndSpacingY
); ;
}
}
/// <summary>
/// 设置布局
/// </summary>
private void SetLayout()
{
layout.startCorner = GridLayoutGroup.Corner.UpperLeft;
layout.childAlignment = TextAnchor.UpperLeft;
layout.constraint = Constraint.Flexible;
if (scrollType == ScrollType.Horizontal)
{
layout.startAxis = GridLayoutGroup.Axis.Vertical;
scrollRect.horizontal = true;
scrollRect.vertical = false;
fixedCount = (maxItemNumWide+3) * maxItemNumHigh;
}
else if (scrollType == ScrollType.Vertical)
{
layout.startAxis = GridLayoutGroup.Axis.Horizontal;
scrollRect.horizontal = false;
scrollRect.vertical = true;
fixedCount = maxItemNumWide * (maxItemNumHigh+3);
}
}
/// <summary>
/// 得到第一个数据的锚点位置
/// </summary>
private void GetFirstItemAnchoredPos()
{
firstItemAnchoredPos = new Vector2
(
layout.padding.left + layout.cellSize.x / 2 ,
-layout.padding.top - layout.cellSize.y / 2
);
Debug.Log("第一个数据锚点:" + firstItemAnchoredPos);
}
#endregion
#region Main
/// <summary>
/// 滑动中
/// </summary>
private void OnScroll(Vector2 v)
{
if (dataList.Count == 0)
{
Debug.LogWarning("先调用SetTotalCount方法设置数据总数量再调用Init方法进行初始化");
return;
}
if (scrollType == ScrollType.Vertical)
{
//向上滑
while (content.anchoredPosition.y >= (layout.padding.top + (headIndex / maxItemNumWide + 1) * layoutCellSizeYAndSpacingY)
&& tailIndex != totalCount - 1)
{
//将数据列表中的第一个元素移动到最后一个
RectTransform item = dataList[0];
dataList.Remove(item);
dataList.Add(item);
//设置位置
SetPos(item , tailIndex + 1);
T itemScript = itemScriptsList[0];
itemScriptsList.Remove(itemScript);
itemScriptsList.Add(itemScript);
SetShow(itemScript , tailIndex + 1);
headIndex++;
tailIndex++;
}
//向下滑
while (content.anchoredPosition.y <= (layout.padding.top + (headIndex / maxItemNumWide + 1) * layoutCellSizeYAndSpacingY)
&& headIndex != 0)
{
//将数据列表中的最后一个元素移动到第一个
RectTransform item = dataList.Last();
dataList.Remove(item);
dataList.Insert(0 , item);
//设置位置
SetPos(item , headIndex - 1);
T itemScript = itemScriptsList.Last();
itemScriptsList.Remove(itemScript);
itemScriptsList.Insert(0 , itemScript);
SetShow(itemScript , headIndex - 1);
headIndex--;
tailIndex--;
}
}
else if (scrollType == ScrollType.Horizontal)
{
//向左滑
while (content.anchoredPosition.x <= layout.padding.left - (headIndex/maxItemNumHigh + 1) * layoutCellSizeXAndSpacingX
&& tailIndex != totalCount - 1)
{
//将数据列表中的第一个元素移动到最后一个
RectTransform item = dataList[0];
dataList.Remove(item);
dataList.Add(item);
//设置位置
SetPos(item , tailIndex + 1);
T itemScript = itemScriptsList[0];
itemScriptsList.Remove(itemScript);
itemScriptsList.Add( itemScript);
SetShow(itemScript , tailIndex + 1);
headIndex++;
tailIndex++;
}
//向右滑
while (content.anchoredPosition.x >= -layout.padding.left - (headIndex / maxItemNumHigh + 1) * layoutCellSizeXAndSpacingX
&& headIndex != 0)
{
// break;
//将数据列表中的最后一个元素移动到第一个
RectTransform item = dataList.Last();
dataList.Remove(item);
dataList.Insert(0 , item);
//设置位置
SetPos(item , headIndex - 1);
T itemScript = itemScriptsList.Last();
itemScriptsList.Remove(itemScript);
itemScriptsList.Insert(0 , itemScript);
SetShow(itemScript , headIndex - 1);
headIndex--;
tailIndex--;
}
}
}
#endregion
#region Tool
/// <summary>
/// 设置位置
/// </summary>
private void SetPos(RectTransform trans , int index)
{
if (scrollType == ScrollType.Horizontal)
{
int rowNum = (int)Math.Ceiling((double)index / maxItemNumHigh);
rowNum = index % maxItemNumHigh == 0 ? rowNum + 1 : rowNum;
//列
int lineNum = index % maxItemNumHigh + 1;
trans.anchoredPosition = new Vector2(
rowNum == 1 ? firstItemAnchoredPos.x : (rowNum - 1) * layoutCellSizeXAndSpacingX + layout.padding.left + layout.cellSize.x / 2 ,
lineNum == 1 ? firstItemAnchoredPos.y : -((lineNum - 1) * layoutCellSizeYAndSpacingY + layout.padding.top + layout.cellSize.y / 2)
);
}
else if (scrollType == ScrollType.Vertical)
{
int rowNum = (int)Math.Ceiling((double)index / maxItemNumWide);
rowNum = index % maxItemNumWide == 0 ? rowNum + 1 : rowNum;
//列
int lineNum = index % maxItemNumWide + 1;
//trans.anchoredPosition = new Vector2(
//lineNum == 1 ? firstItemAnchoredPos.x : (lineNum - 1) * (layout.cellSize.x + layout.spacing.x) + layout.padding.left + layout.cellSize.x / 2 ,
// rowNum == 1 ? firstItemAnchoredPos.y : -((rowNum - 1) * (layout.cellSize.y + layout.spacing.y) + layout.padding.top + layout.cellSize.y / 2)
//);
trans.anchoredPosition = new Vector2(
lineNum == 1 ? firstItemAnchoredPos.x : (lineNum - 1) * layoutCellSizeXAndSpacingX + layout.padding.left + layout.cellSize.x / 2 ,
rowNum == 1 ? firstItemAnchoredPos.y : -((rowNum - 1) * layoutCellSizeYAndSpacingY + layout.padding.top + layout.cellSize.y / 2)
);
}
}
#endregion
#region 外部调用
public InfiniteScrollView(GameObject ga,GameObject itemPrefab)
{
this.itemPrefab = itemPrefab;
Init(ga);
}
private int layoutCellSizeYAndSpacingY, layoutCellSizeXAndSpacingX;
/// <summary>
/// 初始化
/// </summary>
public void Init(GameObject ga)
{
//显示item的界面宽高
maskTranV2 = ga.GetComponent<RectTransform>().sizeDelta;
scrollRect = ga.GetComponent<ScrollRect>();
content = scrollRect.content;
layout = content.GetComponent<GridLayoutGroup>();
scrollRect.onValueChanged.AddListener((Vector2 v) => OnScroll(v));
layoutCellSizeYAndSpacingY = (int)layout.cellSize.y + (int)layout.spacing.y;
layoutCellSizeXAndSpacingX = (int)layout.cellSize.x + (int)layout.spacing.x;
maxItemNumWide = (int)((maskTranV2.x - layout.padding.left - layout.padding.top) / layoutCellSizeXAndSpacingX);
maxItemNumHigh = (int)((maskTranV2.y - layout.padding.right - layout.padding.bottom) / layoutCellSizeYAndSpacingY);
scrollType = scrollRect.horizontal ? ScrollType.Horizontal : ScrollType.Vertical;
//设置布局
SetLayout();
}
public void SetObjectList(List<object> objectList)
{
this.objectList = objectList;
//设置总的item数量
totalCount = objectList.Count;
fixedCount = totalCount <= fixedCount ? totalCount : fixedCount;
//设置Content大小
SetContentSize();
//设置头下标和尾下标
headIndex = 0;
tailIndex = fixedCount - 1;
//实例化Item
InitItem();
//得到第一个Item的锚点位置
GetFirstItemAnchoredPos();
}
/// <summary>
/// 设置显示
/// </summary>
public void SetShow(T itemScript,int index)
{
itemScript.UpdateItem(objectList[index]);
}
/// <summary>
/// 销毁所有的元素
/// </summary>
public void DestoryAll()
{
for (int i = dataList.Count - 1; i >= 0; i--)
{
//Destroy(dataList[i].gameObject);
//DestroyImmediate(dataList[i].gameObject);
}
dataList.Clear();
}
#endregion
}
/// <summary>
/// 滑动类型
/// </summary>
public enum ScrollType
{
Horizontal,//竖直滑动
Vertical,//水平滑动
}