UGUI ScrollRect 简单实现刷新、追加、重用功能

  • scrollrect估计很多项目都会使用到,而一般都不满足项目特殊的需要。unity插件也有很多针对scrollrect进行修改的,大多都非常优秀。只是需要导入比较大的库,为了节省空间,自己就写了个简单的版本来满足项目的需要。

功能需求

  • 下拉出现刷新
  • 上拉出现加载更多
  • 实现多个item的重用

先看看效果
UGUI ScrollRect 简单实现刷新、追加、重用功能_第1张图片
参数控制

public int layoutwidth = 1242;//填写item的长度
public int limitNum = 8;//列表实例化个数
public float interval = 200;//每个item的高度
public float spacing = 5;//每个tiem的间隔

ScrollRect改写思路(只是方法描述)

  1. 捕获ScrollRect的点击、拖放事件进行逻辑修改。

    UIScrollEventListener.Get(scrollRect.gameObject).onDrag = (data) =>
    {
    	//监听drag的事件  位置判断
    }
    
    UIScrollEventListener.Get(scrollRect.gameObject).onUp = (data) =>
    {
    	//此处是监听鼠标点击事件  发出刷新和加载更多事件
    }
    
  2. 页码更新(对页码进行刷新)

    void UpdatePageIndex(int pdex)
     {
    	//刷新页码 ,  item重用功能实现
    }
  1. 设置Refresh 、 Append两个方法,让外部对内item数目进行更改
        public void Refresh(int len)
        {
        		//刷新item列表  抛弃之前所有
		}

        public void Append(int len)
        {
        		//追加item信息
		}
  • 实例化
            scrollcomponent = new CZScrollRect();
            scrollcomponent.prefab = rc.Get(UIClubAssitent.funddetail_info);//需要clone的item预制体
            scrollcomponent.scrollRect = rc.Get(UIClubAssitent.funddetail_scrollview).GetComponent();//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 = $"index = {index}";
        }
		
		//text文本描述刷新
        void OnUpdateTextObj(GameObject obj, int type) {

            Text txt = obj.GetComponent();
            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;
        }

        /// 
        /// 用于控制scrollrect是否能够滑动
        /// (用于等待网络请求等业务)
        /// 
        public bool vertical
        {
            get{
                return scrollRect.vertical;
            }set{
                scrollRect.vertical = value;
            }
        }

        /// 
        /// 是否存在更多
        /// 
        public bool hasMore
        {
            get{
                return bHasMore;
            }set{
                bHasMore = value;
            }
        }

        /// 
        /// 初始化参数
        /// 
        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().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);
            });
        }

        /// 
        /// 刷新页面 (重置长度)
        /// 
        /// 
        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;
        }

        /// 
        /// 追加长度
        /// 
        /// 
        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;
        }

        /// 
        /// 实时刷新页面
        /// 
        /// 
        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;
        }

        /// 
        /// 刷新content的高度
        /// 
        void UpdateUiInfo() {

            //Debug.Log($"opeartLen = {opeartLen}");
            scrollRectContent.sizeDelta = new Vector2(0, Math.Max(opeartLen * (interval + spacing), scrollRect.GetComponent().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;
        }
    }
}



你可能感兴趣的:(unity3d)