Construya una rueda, grupo de objetos cíclicos Unity UGUI ScrollView

Construya una rueda, grupo de objetos cíclicos Unity UGUI ScrollView

Solo usa Mask para corte de pantalla, no depende de ningún otro control UGUI, es una rueda pura.
Las ruedas son puras y la compatibilidad es alta. Conveniente para diversas modificaciones. Bienvenido a intercambiar y discutir.

Para conocer el MonoPool utilizado, consulte el enlace de mi otro artículo: Dejar un archivo, MonoBehaviour Object Pool


Código central:

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

public class ScrollViewEX : MonoBehaviour
{
    public enum Type : byte
    {
        Horizontal, // 横向
        Vertical    // 纵向
    }

    [Header("Base")]
    [SerializeField] Type m_eDirection = Type.Vertical;
    [SerializeField] ScrollViewEX_Item m_prefabItem = null;
    [SerializeField] Image m_PanelRect = null;
    [SerializeField] float m_nDragScale = 0;    // 拖动距离的缩放;

    // data
    private object[] m_arrDatas = null;     // 所有数据
    private MonoPool<ScrollViewEX_Item> m_poolItems = null;   // 对象池
    private float m_nPanelSize = 0;   // 限时范围
    private float m_nItemSize = 0;    // 单个cell尺寸
    private float m_nPosMax = 0;        // 滚动坐标上限

    // runtime
    private Dictionary<int, ScrollViewEX_Item> m_dicShowingItems = new Dictionary<int, ScrollViewEX_Item>(); // 显示中的内容
    private float m_nPos = 0;           // 当前坐标
    private float m_nPosCache = 0;      // 拖拽过程中的坐标

    private void Awake()
    {
        GameObject go = m_PanelRect.gameObject;
        UIEventListener.Get(go).onBeginDrag = OnDragBegin;
        UIEventListener.Get(go).onDrag = OnDraging;
        UIEventListener.Get(go).onEndDrag = OnDragEnd;
        m_poolItems = new MonoPool<ScrollViewEX_Item>(m_prefabItem, this.transform, null, true);

        Vector2 v2PanelSize = m_PanelRect.rectTransform.sizeDelta;
        m_nItemSize = m_eDirection == Type.Horizontal ? m_prefabItem.Size.x : m_prefabItem.Size.y;
        m_nPanelSize = m_eDirection == Type.Horizontal ? v2PanelSize.x : v2PanelSize.y;
    }

    private void Start()
    {
        // 这是一个测试
        Init(new object[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 });
    }

    public void Init(object[] arrDatas)
    {
        m_arrDatas = arrDatas;

        m_nPosMax = m_arrDatas.Length * m_nItemSize - m_nPanelSize;
        if (m_eDirection == Type.Horizontal)
        {
            m_nPosMax = 0 - m_nPosMax;
        }

        Reposition();
    }

    public void Reposition()
    {
        m_nPos = 0;
        MathViewIndexs(0);
        SyncItemsPos(0);
    }
    
    /// <summary>
    /// 刷新范围内需要显示的内容
    /// </summary>
    private void MathViewIndexs(float nPos)
    {
        if (m_eDirection == Type.Horizontal)
        {
            nPos = 0 - nPos;
        }
        float ne = nPos + m_nPanelSize;
        int nCountFrom = (int)(nPos / m_nItemSize);
        int nCountTo = (int)(ne / m_nItemSize);
        if (nCountFrom < 0)
        {
            nCountFrom = 0 - nCountFrom;
        }
        if (nCountTo < 0)
        {
            nCountTo = 0 - nCountTo;
        }
        RefreshList(nCountFrom, nCountTo);
    }

    private void RefreshList(int nFrom, int nTo)
    {
        List<int> listShowing = new List<int>(m_dicShowingItems.Keys);
        for (int i = nFrom; i <= nTo; i++)
        {
            listShowing.Remove(i);
        }
        for (int i = 0; i < listShowing.Count; i++)
        {
            int nKey = listShowing[i];
            var one = m_dicShowingItems[nKey];
            m_dicShowingItems.Remove(nKey);
            one.Release();
            m_poolItems.FreeOne(one);
        }
        for (int i = nFrom; i <= nTo; i++)
        {
            if (i >= m_arrDatas.Length)
            {
                break;
            }
            if (!m_dicShowingItems.ContainsKey(i))
            {
                var item = m_poolItems.GetOne();
                item.m_nDefaultPos = m_nItemSize * 0.5f + i * m_nItemSize;
                item.Init(m_arrDatas[i]);
                m_dicShowingItems.Add(i, item);
            }
        }
    }

    /// <summary>
    /// 刷新所有内容坐标
    /// </summary>
    private void SyncItemsPos(float nPos = 0)
    {
        foreach (var item in m_dicShowingItems)
        {
            SyncItemPos(item.Value, nPos);
        }
    }

    /// <summary>
    /// 同步偏移坐标
    /// </summary>
    private void SyncItemPos(ScrollViewEX_Item item, float nPos)
    {
        Vector3 pos = item.transform.localPosition;
        if (m_eDirection == Type.Horizontal)
        {
            pos.x = item.m_nDefaultPos - m_nPanelSize * 0.5f + nPos;
        }
        else
        {
            pos.y = -item.m_nDefaultPos + m_nPanelSize * 0.5f + nPos;
        }
        item.transform.localPosition = pos;
    }


    private void OnDragBegin(PointerEventData e)
    {
        m_nPosCache = m_nPos;
        m_nPosLastFrame = m_nPosCurFrame = m_nPos;
        m_isPlaySpring = false;
    }

    private void OnDraging(PointerEventData e)
    {
        Vector2 v2Move = e.position - e.pressPosition;
        var movepos = (m_eDirection == Type.Horizontal ? v2Move.x : v2Move.y) * m_nDragScale;
        m_nPosCache = FilterPosInRange(m_nPos + movepos);
        MathViewIndexs(m_nPosCache);
        SyncItemsPos(m_nPosCache);

        m_nPosLastFrame = m_nPosCurFrame;
        m_nPosCurFrame = m_nPosCache;
    }

    private void OnDragEnd(PointerEventData e)
    {
        m_nPos = m_nPosCache;
        PlaySpring();
    }

    [Header("Base-Spring")]
    [SerializeField] float m_nSpringLenScale = 0;           // spring距离倍数
    [SerializeField] float m_nSpringSmoothTime = 0;         // spring时间
    [SerializeField] float m_nSpringStopThreshold = 0;      // 判断是否缓动静止

    private bool m_isPlaySpring = false;

    private float m_nPosLastFrame = 0;  // 记录两帧之间的差异
    private float m_nPosCurFrame = 0;   // 记录两帧之间的差异


    private float m_nPosTarget = 0;     // 缓动 目标位置

    private void PlaySpring()
    {
        m_nPosTarget = m_nPos + (m_nPosCurFrame - m_nPosLastFrame) * m_nSpringLenScale;

        nVelocity = 0;
        m_isPlaySpring = true;
    }

    private float nVelocity = 0.0f; // SmoothDamp 的必要参数

    void Update()
    {
        if (!m_isPlaySpring)
        {
            return;
        }
        m_nPos = Mathf.SmoothDamp(m_nPos, m_nPosTarget, ref nVelocity, m_nSpringSmoothTime);
        m_nPos = FilterPosInRange(m_nPos);
        MathViewIndexs(m_nPos);
        SyncItemsPos(m_nPos);

        float yv = nVelocity < 0 ? (0 - nVelocity) : nVelocity;
        if (yv <= m_nSpringStopThreshold)
        {
            m_isPlaySpring = false;
        }
    }

    private float FilterPosInRange(float nPos)
    {
        float nResult =
            Mathf.Clamp
            (
                nPos,
                m_eDirection == Type.Horizontal ? m_nPosMax : 0,
                m_eDirection == Type.Horizontal ? 0 : m_nPosMax
            );
        return nResult;
    }
}

Clase base de objeto de contenido único

using UnityEngine;

public class ScrollViewEX_Item : MonoBehaviour
{
    [SerializeField] Vector2 m_size = Vector2.zero;

    public virtual Vector2 Size
    {
        get
        {
            return m_size;
        }
    }

    [HideInInspector] public float m_nDefaultPos = 0;

    public virtual void Init(object data)
    {
    }

    public virtual void Release()
    {
    }
}

Script de objeto de contenido para pruebas

using UnityEngine;
using UnityEngine.UI;

public class TestRoundItem : ScrollViewEX_Item
{
    [SerializeField] Text m_txt = null;

    public override void Init(object data)
    {
        m_txt.text = ((int)data).ToString();
    }

    public override void Release()
    {
        m_txt.text = "";
    }
}

Panel en unidad:
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí


La programación es infinita.
Todos son bienvenidos a comunicarse. Si hay algo que no está claro o está mal, también pueden chatear conmigo en privado.
Mi QQ 334524067 Dios-como Didi

Supongo que te gusta

Origin blog.csdn.net/qq_37776196/article/details/126401290
Recomendado
Clasificación