一个很简单的原创 ScrollView

话说那是当年看NGUI的ScrollView,那个迷糊没看懂,后来一直想写个简单的缺迟迟未动手,为啥呢?一脸懵逼

在这时间都不知道丢哪里的时候,硬是海底捞针般的捞起一片片散时,鲁了这个粗糙的ScrollView,忙啥呢?一脸懵逼

扯扯犊子,一天又丢了,丢啥呢?一脸懵逼

此处忽略万脸懵逼

瞎扯完了,记录点东西,好歹是一直写,很粗糙的简版,有待完善,后续再补个完整版吧

本想备注点啥,看这英语,貌似很中文的样子,就不备注 --。-

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;

#if UNITY_EDITOR
using UnityEditor;
#endif

public enum EDirection
{
    Horizontal,
    Vertical,
}

//必要裁切
[RequireComponent(typeof(RectMask2D))]
public class TestScrollView : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
    public delegate void DSetElement(Transform ts, int index);
    public DSetElement SetElement;

    public int Total;               //总数
    public GameObject template;     //模板

    public RectOffset Offset;       //偏移

    public Vector2 ElementSize;     //单元格大小
    public Vector2 Spacing;         //单元格间隔
    public EDirection Direction;    //方向
    public float Smooth = 2.5f;     //平滑速度

    private Vector2 m_ShowBound;    //显示区域
    private Transform m_tsContent;  //显示父级
    private RectTransform m_rtContent;  //显示父级

    private int m_nCurStartIndex;   //当前第一个下标
    private int m_nCurEndIndex;     //当前最后一个下标
    private int m_nColumn;          //列数
    private int m_nRow;             //行数
    private int m_ShowTotal;

    private Vector2 m_fMax;
    private Vector2 m_fMin;
    private Vector2  m_v2EndDetal = Vector2.zero;
    private bool m_bDraging = false;
    private CacahePool m_Pool;

    void Awake()
    {
        if (template == null)
        {
            Debug.LogError("SrollView 缺少模板");
            return;
        }

        m_Pool = new CacahePool(template);

        GameObject goContent = new GameObject();
        goContent.name = "content";
        goContent.transform.SetParent(transform);
        goContent.transform.localRotation = Quaternion.Euler(Vector3.zero);
        goContent.transform.localScale = Vector3.one;

        //锚点设置
        m_rtContent = goContent.AddComponent<RectTransform>();
        m_rtContent.anchorMin = new Vector2(0, 1);
        m_rtContent.anchorMax = new Vector2(0, 1);
        m_rtContent.anchoredPosition = Vector2.zero;

        m_tsContent = goContent.transform;
    }

    public void Initialize()
    {
        m_ShowBound = new Vector2();
        m_ShowBound.x = this.GetComponent<RectTransform>().rect.width;
        m_ShowBound.y = this.GetComponent<RectTransform>().rect.height;

        m_nColumn = Mathf.FloorToInt((m_ShowBound.x - Offset.left - Offset.right + Spacing.x) / (ElementSize.x + Spacing.x));
        m_nRow = Mathf.FloorToInt((m_ShowBound.y - Offset.top - Offset.bottom) / (ElementSize.y + Spacing.y));

        m_ShowTotal = Direction == EDirection.Horizontal ? (m_nColumn + 1) * m_nRow : m_nColumn * (m_nRow + 1);

        m_fMin = new Vector2(0, 0);
        float maxY = 0;
        int readyRow = Mathf.CeilToInt((float)Total / m_nColumn);
        maxY = readyRow * ElementSize.y + (readyRow - 1) * Spacing.y + Offset.top + Offset.bottom - m_ShowBound.y;
        maxY = maxY >= 0 ? maxY : 0;
        m_fMax = new Vector2(0, maxY);

        UpdatePosition(Vector2.zero);
    }

    public void OnBeginDrag(PointerEventData data)
    {
        m_bDraging = true;
    }

    public void OnDrag(PointerEventData data)
    {
        Vector2 delta = data.delta;
        m_v2EndDetal = delta;

        m_v2EndDetal.x = Direction == EDirection.Horizontal ? m_v2EndDetal.x : 0;
        m_v2EndDetal.y = Direction == EDirection.Vertical ? m_v2EndDetal.y : 0;

        UpdatePosition(m_rtContent.anchoredPosition + m_v2EndDetal);
    }

    public void OnEndDrag(PointerEventData data)
    {
        Vector2 delta = data.delta;
        m_bDraging = false;

        Smooth = Direction == EDirection.Horizontal ? m_v2EndDetal.x : m_v2EndDetal.y;
        Smooth = Smooth >= 0 ? Smooth : -Smooth;
        Smooth = Smooth * 0.3f;
    }

	void Update () {
        if (m_bDraging || m_rtContent == null) return;

        Vector2 pos = m_rtContent.anchoredPosition;
        Smooth = Smooth > 5 ? Smooth : 5;
        if (Direction == EDirection.Vertical)
        {
            if (pos.y < m_fMin.y)
            {
                m_v2EndDetal = Vector2.zero;
                if (Vector2.Distance(pos, m_fMin) < 0.1f) return;
                UpdatePosition(Vector2.Lerp(pos, m_fMin, Time.deltaTime * Smooth));
                return;
            }

            if (pos.y > m_fMax.y)
            {
                m_v2EndDetal = Vector2.zero;
                if (Vector2.Distance(pos, m_fMax) < 0.1f) return;
                UpdatePosition(Vector2.Lerp(pos, m_fMax, Time.deltaTime * Smooth));
                return;
            }
        }

        if (m_v2EndDetal == Vector2.zero) return;
        m_v2EndDetal = Vector2.Lerp(m_v2EndDetal, Vector2.zero, Time.deltaTime * Smooth);
        if (m_v2EndDetal.x < 0.1f && m_v2EndDetal.y < 0.1f && m_v2EndDetal.x > -0.1f && m_v2EndDetal.y > -0.1f)
        {
            m_v2EndDetal = Vector2.zero;
        }

        UpdatePosition(m_rtContent.anchoredPosition + m_v2EndDetal);
	}

    void LateUpdate()
    {
        int childCount = m_tsContent.childCount;
        int firstShowIndex = FirstShowIndex;
        int lastShowIndex = LastShowIndex;

        for (int i = 0; i < m_UseList.Count; i++)
        {
            Template tpl = m_UseList[i];
            if (tpl.index < firstShowIndex || tpl.index > lastShowIndex)
            {
                m_Pool.Free(tpl);
                m_UseList.RemoveAt(i);
                i--;
            }
        }
    }

    void UpdatePosition(Vector2 pos)
    {
        m_rtContent.anchoredPosition = pos;
        CheckPosition();
    }

    Vector3 GetPosByIndex(int index)
    {
        int row = Mathf.CeilToInt((float)index / m_nColumn);
        int column = index - (row - 1) * m_nColumn;
        Vector3 pos = new Vector3();

        pos.x = Offset.left + column * ElementSize.x + (column - 1) * Spacing.x - ElementSize.x / 2;
        pos.y = -(Offset.top + row * ElementSize.y + (row - 1) * Spacing.y - ElementSize.y / 2);

        return pos;
    }

    int FirstShowIndex
    {
        get
        {
            int firstShowLine = Mathf.CeilToInt(Mathf.Abs(m_rtContent.anchoredPosition.y - Offset.top) / (ElementSize.y + Spacing.y));
            if (m_rtContent.anchoredPosition.y < 0) firstShowLine = 1;
            return (firstShowLine - 1) * m_nColumn + 1;
        }
    }

    int LastShowIndex
    {
        get
        {
            return FirstShowIndex + m_ShowTotal - 1 + m_nColumn * 2;
        }
    }

    private List<Template> m_UseList = new List<Template>();

    void CheckPosition()
    {
        int curIndex = FirstShowIndex;

        for (int i = 1; i <= m_ShowTotal; i++, curIndex++)
        {
            if (curIndex > Total) return;

            Vector3 pos = GetPosByIndex(curIndex);

            bool bContinue = false;
            for (int j = 0; j < m_UseList.Count; j++)
            {
                Template tpl = m_UseList[j];
                if (tpl.index == curIndex)
                {
                    tpl.ts.localPosition = pos;
                    bContinue = true;
                    break;
                }
            }

            if (bContinue) continue;

            Template newTpl = m_Pool.Get(curIndex);

            newTpl.index = curIndex;
            newTpl.ts.name = curIndex.ToString();
            newTpl.ts.SetParent(m_tsContent);
            newTpl.ts.localRotation = Quaternion.Euler(Vector3.zero);
            newTpl.ts.localScale = Vector3.one;
            newTpl.ts.localPosition = pos;
            newTpl.ts.gameObject.SetActive(true);
            m_UseList.Add(newTpl);

            if (SetElement != null)
            { 
                SetElement(newTpl.ts, curIndex);
            }

            SetElementTest(newTpl.ts, curIndex);
        }
    }

    //测试方法
    void SetElementTest(Transform ts, int index)
    {
        if (SetElement != null)
        {
            SetElement(ts, index);
        }
        ts.Find("Text").GetComponent<Text>().text = index.ToString();
    }

    public void Hide()
    {
        foreach (Template tpl in m_UseList)
        {
            m_Pool.Free(tpl);
        }
        m_UseList.Clear();
    }

    public void Destroy()
    {
        foreach (Template tpl in m_UseList)
        {
            GameObject.Destroy(tpl.ts.gameObject);
        }
        m_UseList.Clear();
        m_Pool.Destroy();
    }

#if UNITY_EDITOR
    void OnGUI()
    {
        //开始绘制GUI
        Handles.BeginGUI();

        //规定GUI显示区域
        GUILayout.BeginArea(new Rect(0, 0, 100, 100));
        if (GUILayout.Button("初始化!"))
        {
            Initialize();
        }

        GUILayout.EndArea();
        Handles.EndGUI();
    }
#endif

    //模板
    public struct Template
    {
        public Transform ts;
        public int index;
    }

    //克隆池
    private class CacahePool
    {
        private GameObject m_goTempalte;
        private List<Template> m_FreeList;

        public CacahePool(GameObject template)
        {
            m_goTempalte = template;
            m_FreeList = new List<Template>();
        }

        public Template Get(int index)
        {
            Template tpl;
            if (m_goTempalte == null)
            {
                Debug.LogError("Template is null");
                m_goTempalte = new GameObject();
            }

            if (m_FreeList.Count > 0)
            {
                int getIndex = 0;
                for (int i = 0; i < m_FreeList.Count; i++)
                {
                    if (m_FreeList[i].index == index)
                    {
                        getIndex = i;
                    }
                }

                tpl = m_FreeList[getIndex];
                m_FreeList.RemoveAt(getIndex);
            }
            else
            {
                Template newTpl = new Template();
                newTpl.ts = GameObject.Instantiate<GameObject>(m_goTempalte).transform;
                tpl = newTpl;
            }

            return tpl;
        }

        public void Free(Template tpl)
        {
            tpl.ts.gameObject.SetActive(false);
            m_FreeList.Add(tpl);
        }

        public void Destroy()
        {
            foreach (Template tpl in m_FreeList)
            {
                GameObject.Destroy(tpl.ts.gameObject);
            }
            m_FreeList.Clear();
        }
    }
}

https://download.csdn.net/download/u014236515/10547690 

上面连接是unitypackage文件,现在至少要1积分的样,貌似不能设置0分

版本u3d 2017.3.1 直接导入项目即刻

后续有空再更新,此贴仅做个记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值