UGUI—UIListView

作者:追风剑情 发布于:2019-11-4 17:56 分类:Unity3d

一、工程截图

222.png

3333.png

444.png

5555.png

二、代码实现

UIListView.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
/// <summary>
/// 自定义UIList
/// </summary>
public class UIListView : UIBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    public RectTransform root;
    public RectTransform itemTemplet;
    public Rect rect;
    public int count;
    public float space; //间隔距离
    public float itemHeight;
    public float KickBackSpeed = 1;
    public float MoveSpeed = 1;
    private List<RectTransform> list;

    public delegate bool OnFillDataCallback(int index, GameObject go);
    public OnFillDataCallback OnFillData;

    private RectTransform m_RectTransform;
    private MoveDirection m_MoveDirection;
    private MoveState m_MoveState;
    private float m_TotalHeight;
    private float m_LastDragTime = 0;
    private Vector2 m_LastDragPosition;
    private float m_MoveY;
    private float t;

    public RectTransform rectTransform
    {
        get
        {
            if (ReferenceEquals(m_RectTransform, null))
            {
                m_RectTransform = GetComponent<RectTransform>();
            }
            return m_RectTransform;
        }
    }

    protected override void Start()
    {
        itemTemplet.gameObject.SetActive(false);
        float y = 0;
        for (int i=0; i<count; i++)
        {
            y = -(itemHeight + space) * i;
            RectTransform tran = CreateItem();
            SetPosition(tran, 0, y);
            //通过回调方法给选项设值
            if (OnFillData != null)
                OnFillData(i, tran.gameObject);
        }
        m_TotalHeight = Mathf.Abs(y) + itemHeight;

        RectMask2D mask = this.gameObject.AddComponent<RectMask2D>();
        mask.PerformClipping();
    }

    private void Update()
    {
        if (m_MoveState == MoveState.KickBack)
        {
            t += Time.deltaTime * KickBackSpeed;
            if (PositionY < 0)
                PositionY = Mathf.SmoothStep(PositionY, 0, t);
            else if (PositionY > MinPositionY)
                PositionY = Mathf.SmoothStep(PositionY, MinPositionY, t);
            else
                m_MoveState = MoveState.Static;
        } 
        else if (m_MoveState == MoveState.Moving)
        {
            t += Time.deltaTime * MoveSpeed;
            MoveSpeed /= 2;
            Debug.Log(MoveSpeed);
            PositionY = Mathf.SmoothStep(PositionY, m_MoveY, t);
            if (t >= 1 || MoveSpeed <= 0)
                m_MoveState = MoveState.Static;
        }
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        m_MoveState = MoveState.Static;
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector2 delta = eventData.delta;
        SetDeltaPosition(root, 0, delta.y);
        m_MoveDirection = delta.y > 0 ? MoveDirection.Up : MoveDirection.Down;
        m_MoveState = MoveState.Dragging;
        m_LastDragTime = Time.time;
        m_LastDragPosition = eventData.position;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        t = 0;
        m_MoveState = PositionY > MinPositionY || PositionY < 0 ? MoveState.KickBack : MoveState.Static;
        if (PositionY > MinPositionY || PositionY < 0)
        {
            m_MoveState = MoveState.KickBack;
        }
        else
        {
            if (Time.time - m_LastDragTime < 0.5f)
            {
                float time = Time.time - m_LastDragTime;
                float s = eventData.position.y - m_LastDragPosition.y;
                MoveSpeed = Mathf.Abs(s) / time / 1000;
                if (Mathf.Abs(s) > 1)
                {
                    m_MoveY = PositionY + s * 5000;
                    if (m_MoveY < 0)
                        m_MoveY = 0;
                    else if (m_MoveY > MinPositionY)
                        m_MoveY = MinPositionY;
                    m_MoveState = MoveState.Moving;
                    t = 0;
                }
                else
                {
                    m_MoveState = MoveState.Static;
                }
            }
            else
            {
                m_MoveState = MoveState.Static;
            }
        }
        
    }

    private RectTransform CreateItem()
    {
        RectTransform tran = GameObject.Instantiate<RectTransform>(itemTemplet);
        tran.SetParent(root);
        tran.gameObject.SetActive(true);
        return tran;
    }

    private void SetPosition(RectTransform tran, float x, float y)
    {
        tran.anchoredPosition = new Vector2(x, y);
    }

    private void SetDeltaPosition(RectTransform tran, float deltaX, float deltaY)
    {
        Vector2 pos = tran.anchoredPosition;
        pos.x += deltaX;
        pos.y += deltaY;
        tran.anchoredPosition = pos;
    }

    private float PositionY
    {
        get
        {
            return root.anchoredPosition.y;
        }
        set
        {
            SetPosition(root, 0, value);
        }
    }

    private float MinPositionY
    {
        get
        {
            if (m_TotalHeight <= rect.height)
                return 0;
            return m_TotalHeight - rect.height;
        }
    }

    private float BottomPositionY
    {
        get
        {
            return m_TotalHeight;
        }
    }

    private enum MoveDirection
    {
        None,
        Up,
        Down
    }

    private enum MoveState
    {
        Static,   //静止
        Dragging, //拖拽
        Moving,   //移动
        KickBack, //回弹
    }
}

UIListItem.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
/// <summary>
/// 列表选项
/// </summary>
public class UIListItem : MonoBehaviour, IPointerClickHandler
{
    public Text text;
    public void SetText(string s)
    {
        this.text.text = s;
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("Click: " + text.text);
    }
}

UIListViewTest.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 测试
/// </summary>
public class UIListViewTest : MonoBehaviour
{
    void Awake()
    {
        UIListView listView = this.GetComponent<UIListView>();
        listView.OnFillData = new UIListView.OnFillDataCallback(OnFillData);
    }

    private bool OnFillData(int index, GameObject go)
    {
        Debug.LogFormat("OnFillData({0}, go)", index, go);
        UIListItem item = go.GetComponent<UIListItem>();
        item.SetText("Number " + index);

        return true;
    }
    
}

三、运行效果

11111.gif

标签: Unity3d

Powered by emlog  蜀ICP备18021003号   sitemap

川公网安备 51019002001593号