UGUI ScrollRect 简单实现刷新、追加、重用功能
- scrollrect估计很多项目都会使用到,而一般都不满足项目特殊的需要。unity插件也有很多针对scrollrect进行修改的,大多都非常优秀。只是需要导入比较大的库,为了节省空间,自己就写了个简单的版本来满足项目的需要。
功能需求
- 下拉出现刷新
- 上拉出现加载更多
- 实现多个item的重用
先看看效果
参数控制
public int layoutwidth = 1242;//填写item的长度
public int limitNum = 8;//列表实例化个数
public float interval = 200;//每个item的高度
public float spacing = 5;//每个tiem的间隔
ScrollRect改写思路(只是方法描述)
-
捕获ScrollRect的点击、拖放事件进行逻辑修改。
UIScrollEventListener.Get(scrollRect.gameObject).onDrag = (data) => { //监听drag的事件 位置判断 } UIScrollEventListener.Get(scrollRect.gameObject).onUp = (data) => { //此处是监听鼠标点击事件 发出刷新和加载更多事件 }
-
页码更新(对页码进行刷新)
void UpdatePageIndex(int pdex)
{
//刷新页码 , item重用功能实现
}
- 设置Refresh 、 Append两个方法,让外部对内item数目进行更改
public void Refresh(int len)
{
//刷新item列表 抛弃之前所有
}
public void Append(int len)
{
//追加item信息
}
- 实例化
scrollcomponent = new CZScrollRect();
scrollcomponent.prefab = rc.Get<GameObject>(UIClubAssitent.funddetail_info);//需要clone的item预制体
scrollcomponent.scrollRect = rc.Get<GameObject>(UIClubAssitent.funddetail_scrollview).GetComponent<ScrollRect>();//scrollRect对象
scrollcomponent.text_up = scrollcomponent.scrollRect.content.GetChild(0).gameObject;//text文本
scrollcomponent.text_down = scrollcomponent.scrollRect.content.GetChild(1).gameObject;//text文本
scrollcomponent.onRefresh = OnRefresh;//注册事件
scrollcomponent.onAppend = OnAppend;//注册事件
scrollcomponent.onScrollObj = OnScrollObj;//注册事件
scrollcomponent.onUpdateTextObj = OnUpdateTextObj;//注册事件
scrollcomponent.Init();//实例化
- 注册事件的实现
//刷新对象
void OnScrollObj(GameObject obj , int index) {
//Debug.Log($"OnScrollObj -- {obj.name} index = {index}");
obj.transform.GetChild(0).GetComponent<Text>().text = $"index = {index}";
}
//text文本描述刷新
void OnUpdateTextObj(GameObject obj, int type) {
Text txt = obj.GetComponent<Text>();
switch (type) {
case 0:
txt.text = "松开可以刷新";
break;
case 1:
txt.text = "下拉可以刷新";
break;
case 2:
txt.text = "松开可以加载更多";
break;
case 3:
txt.text = "没有更多数据了";
break;
case 4:
txt.text = "上拉可以加载更多";
break;
default:
txt.text = "unknow";
break;
}
}
//随机数对列表刷新
void OnRefresh() {
int r = UnityEngine.Random.Range(1, 5);
scrollcomponent.Refresh(r);
}
//随机对列表追加个数
void OnAppend()
{
int r = UnityEngine.Random.Range(0, 10);
scrollcomponent.Append(r);
}
- 附上全部代码内容
学习愉快
using System;
using System.Collections.Generic;
using System.Net;
using BestHTTP;
using ETModel;
using UnityEngine;
using UnityEngine.UI;
namespace ETHotfix
{
public class ScrollObj
{
public GameObject obj;
public int dex;
}
public class CZScrollRect
{
const int OPEAT_HEIGHT = 100;//高度差判断操作类型
const int INIT_NUM_LIMIT = 8;//列表实例化个数
public delegate void OperatDelegate();
public delegate void OperatObjDelegate(GameObject obj , int index);
public OperatDelegate onRefresh;//下拉刷新时回调
public OperatDelegate onAppend;//需要加载更多时回调
public OperatObjDelegate onScrollObj;//需刷新时回调
public OperatObjDelegate onUpdateTextObj;//需刷新文本状态时回调
public ScrollRect scrollRect;//ScrollRect
private RectTransform scrollRectContent;//RectTransform
public GameObject prefab;//实例化的对象
public GameObject text_up;//下拉刷新文本
public GameObject text_down;//上拉加载更多文本
int textup_status;
int textdown_status;
int opeartLen = 0;//记录总长度
public int layoutwidth = 1242;//填写item的长度
public int limitNum = 8;//列表实例化个数
public float interval = 200;//每个item的高度
public float spacing = 5;//每个tiem的间隔
ScrollObj[] list;//用于管理生成的对象
int opeartType;
int pageindex;//页码
bool bHasMore;//是否能加载更多
int halfWidth;
public CZScrollRect()
{
opeartType = -1;
hasMore = false;
}
/// <summary>
/// 用于控制scrollrect是否能够滑动
/// (用于等待网络请求等业务)
/// </summary>
public bool vertical
{
get{
return scrollRect.vertical;
}set{
scrollRect.vertical = value;
}
}
/// <summary>
/// 是否存在更多
/// </summary>
public bool hasMore
{
get{
return bHasMore;
}set{
bHasMore = value;
}
}
/// <summary>
/// 初始化参数
/// </summary>
public void Init() {
list = new ScrollObj[Mathf.Max(limitNum, INIT_NUM_LIMIT)];
scrollRectContent = scrollRect.content;
halfWidth = layoutwidth / 2;
//此处监听drag事件
UIScrollEventListener.Get(scrollRect.gameObject).onDrag = (data) =>
{
float recty = -scrollRectContent.rect.y - scrollRect.GetComponent<RectTransform>().sizeDelta.y;//Log.Debug($"{scrollRectContent.anchoredPosition.y} , {recty} , {-scrollRectContent.rect.y}");
if (scrollRectContent.anchoredPosition.y >= recty + OPEAT_HEIGHT)
{
if (bHasMore)
{
//松开可以加载更多
if (textup_status != 2) {
textup_status = 2;
if (onUpdateTextObj != null) onUpdateTextObj(text_down, 2);
}
}
else
{
//没有更多数据了
if (textup_status != 3)
{
textup_status = 3;
if (onUpdateTextObj != null) onUpdateTextObj(text_down, 3);
}
}
opeartType = 1;
}
else if (scrollRectContent.anchoredPosition.y > recty)
{
if (bHasMore)
{
//上拉可以加载更多
if (textup_status != 4)
{
textup_status = 4;
if (onUpdateTextObj != null) onUpdateTextObj(text_down, 4);
}
}
else
{
//没有更多数据了
if (textup_status != 3)
{
textup_status = 3;
if (onUpdateTextObj != null) onUpdateTextObj(text_down, 3);
}
}
opeartType = -1;
}
else if (scrollRectContent.anchoredPosition.y <= -OPEAT_HEIGHT)
{
//松开可以刷新
if (textup_status != 0)
{
textup_status = 0;
if (onUpdateTextObj != null) onUpdateTextObj(text_up, 0);
}
opeartType = 0;
}
else if (scrollRectContent.anchoredPosition.y < 0)
{
//下拉可以刷新
if (textup_status != 1)
{
textup_status = 1;
if (onUpdateTextObj != null) onUpdateTextObj(text_up, 1);
}
opeartType = -1;
}
else
{
opeartType = -1;
}
};
//此处是监听鼠标点击事件
UIScrollEventListener.Get(scrollRect.gameObject).onUp = (data) =>
{
if (opeartType == 0)
{
if (onRefresh != null)
{
scrollRect.vertical = false;
onRefresh();
}
}
else if (opeartType == 1)
{
if (bHasMore && onRefresh != null)
{
scrollRect.vertical = false;
onAppend();
}
}
};
scrollRect.onValueChanged.RemoveAllListeners();
scrollRect.onValueChanged.AddListener((v) => {
//TOP TO BUTTOM 计算页码
int curIndex = Mathf.Min(Mathf.Max(Mathf.FloorToInt(scrollRectContent.anchoredPosition.y / interval) - 1, 0), opeartLen - limitNum);
UpdatePageIndex(curIndex);
});
}
/// <summary>
/// 刷新页面 (重置长度)
/// </summary>
/// <param name="len"></param>
public void Refresh(int len)
{
//Debug.Log($"Refresh len = {len}");
if (len < 0) return;
int count = 0;
for (int i = 0; i < list.Length; ++i) {
if (list[i] == null) list[i] = new ScrollObj();
if (i < len) {
if (list[i].obj == null)
{
list[i].obj = GameObject.Instantiate(prefab, scrollRectContent);
}
list[i].dex = i;
list[i].obj.SetActive(true);
list[i].obj.transform.localPosition = new Vector3(halfWidth, - i * (interval + spacing) - interval / 2, 0);
if (onScrollObj != null) onScrollObj(list[i].obj, list[i].dex);
count++;
}
else
{
if(list[i].obj != null) list[i].obj.SetActive(false);
}
}
opeartLen = len;
UpdatePageIndex(0);//重置页码
scrollRectContent.localPosition = Vector3.zero;
scrollRect.verticalScrollbar.value = 1;
UpdateUiInfo();
scrollRect.vertical = true;
}
/// <summary>
/// 追加长度
/// </summary>
/// <param name="len"></param>
public void Append(int len)
{
//Debug.Log($"Append len = {len}");
if (len < 0) return;
if (opeartLen < list.Length) {
int showlen = Mathf.Min(list.Length - opeartLen , len);//Debug.Log($"showlen = {showlen}");
for (int i = 0; i < showlen; ++i) {
int dex = opeartLen + i;//Debug.Log(dex);
if (list[dex] == null) list[dex] = new ScrollObj();
if (list[dex].obj == null)
{
list[dex].obj = GameObject.Instantiate(prefab, scrollRectContent);
}
list[dex].dex = dex;
list[dex].obj.SetActive(true);
list[dex].obj.transform.localPosition = new Vector3(halfWidth, -dex * (interval + spacing) - interval / 2, 0);
if (onScrollObj != null) onScrollObj(list[dex].obj, list[dex].dex);
}
}
opeartLen += len;
UpdateUiInfo();
scrollRect.vertical = true;
}
/// <summary>
/// 实时刷新页面
/// </summary>
/// <param name="pdex"></param>
void UpdatePageIndex(int pdex) {
if (opeartLen <= list.Length || pageindex == pdex) return;//Debug.Log($"pdex = {pdex}");
int x = Mathf.FloorToInt(pdex / limitNum);
int y = pdex % limitNum;
for (int i = 0; i < limitNum; ++i)
{
int d = 0;
if (i < y)
{
d = (x + 1) * limitNum + i;
}
else
{
d = Mathf.Max(x, 0) * limitNum + i;
}
if (list[i].dex != d) {
list[i].dex = d;
if (list[i].obj != null) {
if (onScrollObj != null) onScrollObj(list[i].obj, list[i].dex);
list[i].obj.transform.localPosition = new Vector3(halfWidth, -list[i].dex * (interval + spacing) - interval / 2, 0);
}
}
}
pageindex = pdex;
}
/// <summary>
/// 刷新content的高度
/// </summary>
void UpdateUiInfo() {
//Debug.Log($"opeartLen = {opeartLen}");
scrollRectContent.sizeDelta = new Vector2(0, Math.Max(opeartLen * (interval + spacing), scrollRect.GetComponent<RectTransform>().sizeDelta.y));
if(text_up != null) text_up.transform.localPosition = new Vector3(text_up.transform.localPosition.x, OPEAT_HEIGHT - 50, 0);
if (text_down != null) text_down.transform.localPosition = new Vector3(text_down.transform.localPosition.x, -scrollRectContent.sizeDelta.y - OPEAT_HEIGHT + 50, 0);
}
public void Dispose()
{
scrollRect.onValueChanged.RemoveAllListeners();
scrollRect = null;
scrollRectContent = null;
prefab = null;
text_up = null;
text_down = null;
list = null;
onAppend = null;
onRefresh = null;
onScrollObj = null;
}
}
}