Unity2D_列表滑动

 

其他大佬开发的,只是做个流程备忘

GitHub页面icon-default.png?t=M3K6https://github.com/NRatel/Unity-ListView


流程参考

创建一个图像生成Canvas画布

Unity2D_列表滑动_第1张图片

设置画布匹配相机视野

Unity2D_列表滑动_第2张图片 

Image图像对象用来挂载脚本,移除Image组件

Unity2D_列表滑动_第3张图片

 挂载脚本

Unity2D_列表滑动_第4张图片

 再新建一个图像对象用于遮罩

Unity2D_列表滑动_第5张图片

 给对象添加遮罩组件

Unity2D_列表滑动_第6张图片

 继续新建图像对象作为容器层,移除Image组件并添加内容尺寸适应器和水平布局组组件

Unity2D_列表滑动_第7张图片

Unity2D_列表滑动_第8张图片 

Unity2D_列表滑动_第9张图片设置图像对象合适的大小

Unity2D_列表滑动_第10张图片 拖动调整容器层的位置到合适坐标

Unity2D_列表滑动_第11张图片

 继续添加要滑动的图像对象

Unity2D_列表滑动_第12张图片

可以取消遮罩方便观察调整

Unity2D_列表滑动_第13张图片 

 回到挂载的脚本组件并进行配置

Unity2D_列表滑动_第14张图片

运行即可查看效果


当前版本的脚本代码:

using System;
using UnityEngine.Events;
using UnityEngine.EventSystems;

namespace UnityEngine.UI.Extensions
{
    [SelectionBase]
    [ExecuteInEditMode]
    [DisallowMultipleComponent]
    [RequireComponent(typeof(RectTransform))]
    [AddComponentMenu("UI/Extensions/PagingView")]
    public class PagingView : UIBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler, ICanvasElement, ILayoutElement, ILayoutGroup
    {
        [Serializable] public class PagingEvent : UnityEvent {}

        [SerializeField] private RectTransform m_Content;
        public RectTransform Content
        {
            get { return m_Content; }
            set { m_Content = value; }
        }

        [SerializeField] private RectTransform[] m_Contents;
        public RectTransform[] Contents
        {
            get { return m_Contents; }
            set { m_Contents = value; }
        }

        [SerializeField] private bool m_Horizontal = true;
        public bool Horizontal
        {
            get { return m_Horizontal; }
            set { m_Horizontal = value; }
        }

        [SerializeField] private bool m_Vertical = true;
        public bool Vertical
        {
            get { return m_Vertical; }
            set { m_Vertical = value; }
        }

        [SerializeField] private float m_Elasticity = 0.1f;
        public float Elasticity
        {
            get { return m_Elasticity; }
            set { m_Elasticity = value; }
        }

        [SerializeField] private bool m_Inertia = true;
        public bool Inertia
        {
            get { return m_Inertia; }
            set { m_Inertia = value; }
        }

        [SerializeField] private float m_DecelerationRate = 0.135f;
        public float DecelerationRate
        {
            get { return m_DecelerationRate; }
            set { m_DecelerationRate = value; }
        }

        [SerializeField] private float m_ScrollSensitivity = 1.0f;
        public float ScrollSensitivity
        {
            get { return m_ScrollSensitivity; }
            set { m_ScrollSensitivity = value; }
        }

        [SerializeField] private RectTransform m_Viewport;
        public RectTransform viewport
        {
            get {return m_Viewport; }
            set { m_Viewport = value; SetDirtyCaching(); }
        }

        [SerializeField] private PagingEvent m_OnValueChanged = new PagingEvent();
        public PagingEvent OnValueChanged
        {
            get { return m_OnValueChanged; }
            set { m_OnValueChanged = value; }
        }

        private Vector2 m_PointerStartLocalCursor = Vector2.zero;
        private Vector2 m_ContentStartPosition = Vector2.zero;

        private RectTransform m_ViewRect;
        public RectTransform ViewRect
        {
            get
            {
                if (m_ViewRect == null)
                    m_ViewRect = m_Viewport;
                if (m_ViewRect == null)
                    m_ViewRect = (RectTransform) transform;
                return m_ViewRect;
            }
        }

        [NonSerialized] private RectTransform m_Rect;
        private RectTransform RectTransform
        {
            get
            {
                if (m_Rect == null)
                    m_Rect = GetComponent();
                return m_Rect;
            }
        }

        private Vector2 m_Velocity;
        public Vector2 Velocity
        {
            get { return m_Velocity; }
            set { m_Velocity = value; }
        }

        private bool m_Dragging;

        private Bounds m_ViewBounds;
        private Bounds m_ContentBounds;
        private Bounds m_CurrentContentBounds;
        private Bounds m_PrevViewBounds;
        private Bounds m_PrevContentBounds;
        private Bounds m_PrevCurrentContentBounds;
        private Vector2 m_PrevPosition = Vector2.zero;

        private DrivenRectTransformTracker m_Tracker;

        [NonSerialized] private bool m_HasRebuiltLayout;

        private const float EPSILON = float.Epsilon;

        protected PagingView()
        {
            flexibleWidth = -1;
        }

        public void Rebuild(CanvasUpdate executing)
        {
            if (executing == CanvasUpdate.PostLayout)
            {
                UpdateBounds();
                UpdatePrevData();

                m_HasRebuiltLayout = true;
            }
        }

        protected override void OnRectTransformDimensionsChange()
        {
            SetDirty();
        }

        public virtual void LayoutComplete() {}

        public virtual void GraphicUpdateComplete() {}

        public virtual void CalculateLayoutInputHorizontal() {}

        public virtual void CalculateLayoutInputVertical() {}

        public virtual float minWidth { get { return -1; } }

        public virtual float preferredWidth { get { return -1; } }

        public virtual float flexibleWidth { get; private set; }

        public virtual float minHeight { get { return -1; } }

        public virtual float preferredHeight { get { return -1; } }

        public virtual float flexibleHeight { get { return -1; } }

        public virtual int layoutPriority { get { return -1; } }

        public virtual void SetLayoutHorizontal() { m_Tracker.Clear(); }

        public virtual void SetLayoutVertical()
        {
            m_ViewBounds = new Bounds(ViewRect.rect.center, ViewRect.rect.size);
            m_ContentBounds = GetBounds(m_Content);
            m_CurrentContentBounds = GetBounds(m_Contents[m_ContentIndex]);
        }

        public virtual void OnScroll(PointerEventData eventData)
        {
            if (!IsActive())
                return;

            EnsureLayoutHasRebuilt();
            UpdateBounds();

            Vector2 delta = eventData.scrollDelta;
            delta.y *= -1;
            if (Vertical && !Horizontal)
            {
                if (Mathf.Abs(delta.x) > Mathf.Abs(delta.y))
                    delta.y = delta.x;
                delta.x = 0;
            }

            if (Horizontal && !Vertical)
            {
                if (Mathf.Abs(delta.y) > Mathf.Abs(delta.x))
                    delta.x = delta.y;
                delta.y = 0;
            }

            Vector2 position = m_Content.anchoredPosition;
            position += delta * m_ScrollSensitivity;

            SetContentAnchoredPosition(position);
            UpdateBounds();
        }

        public void OnInitializePotentialDrag(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;

            m_Velocity = Vector2.zero;
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;

            if (!IsActive())
                return;

            UpdateBounds();

            m_PointerStartLocalCursor = Vector2.zero;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(ViewRect, eventData.position,
                eventData.pressEventCamera, out m_PointerStartLocalCursor);
            m_ContentStartPosition = m_Content.anchoredPosition;
            m_Dragging = true;
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;

            m_Dragging = false;

            JudgementIndex();
        }

        public void OnDrag(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;

            if (!IsActive())
                return;

            Vector2 localCursor;
            if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(ViewRect, eventData.position,
                eventData.pressEventCamera, out localCursor))
                return;

            UpdateBounds();

            var pointerDelta = localCursor - m_PointerStartLocalCursor;
            Vector2 position = m_ContentStartPosition + pointerDelta;
            Vector2 offset = CalculateOffset(m_ContentBounds, position - m_Content.anchoredPosition);
            position += offset;
            if (Math.Abs(offset.x) > EPSILON)
                position.x = position.x - RubberDelta(offset.x, m_ViewBounds.size.x);
            if (Math.Abs(offset.y) > EPSILON)
                position.y = position.y - RubberDelta(offset.y, m_ViewBounds.size.y);

            SetContentAnchoredPosition(position);
        }

        protected override void OnEnable()
        {
            base.OnEnable();

            CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
        }

        protected override void OnDisable()
        {
            CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);

            m_Tracker.Clear();
            m_Velocity = Vector2.zero;
            LayoutRebuilder.MarkLayoutForRebuild(RectTransform);

            base.OnDisable();
        }

        public override bool IsActive()
        {
            return base.IsActive() && m_Content != null;
        }

        private int m_PrevContentIndex;
        private int m_ContentIndex;
        private void LateUpdate()
        {
            if (!m_Content)
                return;

            EnsureLayoutHasRebuilt();
            UpdateBounds();
            float deltaTime = Time.unscaledDeltaTime;
            Vector2 offset = CalculateOffset(m_CurrentContentBounds, Vector2.zero);
            if (!m_Dragging && (offset != Vector2.zero || m_Velocity != Vector2.zero))
            {
                Vector2 position = m_Content.anchoredPosition;
                for (int axis = 0; axis < 2; ++axis)
                {
                    if (Math.Abs(offset[axis]) > EPSILON)
                    {
                        float speed = m_Velocity[axis];
                        position[axis] = Mathf.SmoothDamp(m_Content.anchoredPosition[axis], m_Content.anchoredPosition[axis] + offset[axis], ref speed, m_Elasticity, Mathf.Infinity, deltaTime);
                        m_Velocity[axis] = speed;
                    }
                    else if (m_Inertia)
                    {
                        m_Velocity[axis] *= Mathf.Pow(m_DecelerationRate, deltaTime);
                        if (Mathf.Abs(m_Velocity[axis]) < 1)
                            m_Velocity[axis] = 0;
                        position[axis] += m_Velocity[axis] * deltaTime;
                    }
                    else
                    {
                        m_Velocity[axis] = 0;
                    }
                }

                if (m_Velocity != Vector2.zero)
                    SetContentAnchoredPosition(position);
            }

            if (m_Dragging && m_Inertia)
            {
                Vector3 newVelocity = (m_Content.anchoredPosition - m_PrevPosition) / deltaTime;
                m_Velocity = Vector3.Lerp(m_Velocity, newVelocity, deltaTime * 10);
            }

            if (m_Dragging && m_Velocity != Vector2.zero)
                JudgementIndex(offset);

            if (!m_Dragging && m_PrevContentIndex != m_ContentIndex)
            {
                m_OnValueChanged.Invoke(m_ContentIndex);
                m_PrevContentIndex = m_ContentIndex;
            }

            if (m_ViewBounds != m_PrevViewBounds || m_ContentBounds != m_PrevContentBounds
                || m_ContentBounds != m_PrevCurrentContentBounds || m_Content.anchoredPosition != m_PrevPosition)
                UpdatePrevData();
        }

        public virtual void StopMovement()
        {
            m_Velocity = Vector2.zero;
        }

        protected virtual void SetContentAnchoredPosition(Vector2 position)
        {
            if (!m_Horizontal)
                position.x = m_Content.anchoredPosition.x;
            if (!m_Vertical)
                position.y = m_Content.anchoredPosition.y;

            if (position != m_Content.anchoredPosition)
            {
                m_Content.anchoredPosition = position;
                UpdateBounds();
            }
        }

        private void EnsureLayoutHasRebuilt()
        {
            if (m_HasRebuiltLayout && !CanvasUpdateRegistry.IsRebuildingLayout())
                Canvas.ForceUpdateCanvases();
        }

        private void UpdatePrevData()
        {
            if (m_Content == null)
                m_PrevPosition = Vector2.zero;
            else
                m_PrevPosition = m_Content.anchoredPosition;
            m_PrevViewBounds = m_ViewBounds;
            m_PrevContentBounds = m_ContentBounds;
            m_PrevCurrentContentBounds = m_ContentBounds;
        }

        private static float RubberDelta(float overStretching, float viewSize)
        {
            return (1 - (1 / ((Mathf.Abs(overStretching) * 0.55f / viewSize) + 1)))
                   * viewSize * Mathf.Sign(overStretching);
        }

        private void UpdateBounds()
        {
            m_ViewBounds = new Bounds(ViewRect.rect.center, ViewRect.rect.size);
            m_ContentBounds = GetBounds(m_Content);
            m_CurrentContentBounds = GetBounds(m_Contents[m_ContentIndex]);

            if (m_Content == null)
                return;

            Vector3 contentSize = m_ContentBounds.size;
            Vector3 contentPos = m_ContentBounds.center;
            Vector3 excess = m_ViewBounds.size - contentSize;
            if (excess.x > 0)
            {
                contentPos.x -= excess.x * (m_Content.pivot.x - 0.5f);
                contentSize.x = m_ViewBounds.size.x;
            }
            if (excess.y > 0)
            {
                contentPos.y -= excess.y * (m_Content.pivot.y - 0.5f);
                contentSize.y = m_ViewBounds.size.y;
            }

            m_ContentBounds.size = contentSize;
            m_ContentBounds.center = contentPos;
        }

        private readonly Vector3[] m_Corners = new Vector3[4];
        private Bounds GetBounds(RectTransform content)
        {
            if (m_Content == null)
                return new Bounds();

            var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            var toLocal = ViewRect.worldToLocalMatrix;
            content.GetWorldCorners(m_Corners);
            for (int j = 0; j < 4; j++)
            {
                Vector3 v = toLocal.MultiplyPoint3x4(m_Corners[j]);
                vMin = Vector3.Min(v, vMin);
                vMax = Vector3.Max(v, vMax);
            }

            var bounds = new Bounds(vMin, Vector3.zero);
            bounds.Encapsulate(vMax);
            return bounds;
        }

        private Vector2 CalculateOffset(Bounds bounds, Vector2 delta)
        {
            Vector2 offset = Vector2.zero;

            Vector2 min = bounds.min;
            Vector2 max = bounds.max;

            if (m_Horizontal)
            {
                min.x += delta.x;
                max.x += delta.x;
                if (min.x > m_ViewBounds.min.x)
                    offset.x = m_ViewBounds.min.x - min.x;
                else if (max.x < m_ViewBounds.max.x)
                    offset.x = m_ViewBounds.max.x - max.x;
            }

            if (m_Vertical)
            {
                min.y += delta.y;
                max.y += delta.y;
                if (max.y < m_ViewBounds.max.y)
                    offset.y = m_ViewBounds.max.y - max.y;
                else if (min.y > m_ViewBounds.min.y)
                    offset.y = m_ViewBounds.min.y - min.y;
            }

            return offset;
        }

        private void JudgementIndex()
        {
            if (Horizontal)
            {
                if (-m_Velocity.x > m_ViewBounds.size.x)
                    m_ContentIndex = Mathf.Clamp(m_PrevContentIndex + 1, 0, m_Contents.Length - 1);
                else if (m_Velocity.x > m_ViewBounds.size.x)
                    m_ContentIndex = Mathf.Clamp(m_PrevContentIndex - 1, 0, m_Contents.Length - 1);
            }

            if (Vertical)
            {
                if (m_Velocity.y > m_ViewBounds.size.y)
                    m_ContentIndex = Mathf.Clamp(m_PrevContentIndex + 1, 0, m_Contents.Length - 1);
                else if (-m_Velocity.y > m_ViewBounds.size.y)
                    m_ContentIndex = Mathf.Clamp(m_PrevContentIndex - 1, 0, m_Contents.Length - 1);
            }
        }

        private void JudgementIndex(Vector2 offset)
        {
            if (Horizontal)
            {
                if (offset.x > m_ViewBounds.extents.x)
                    m_ContentIndex = Mathf.Clamp(m_ContentIndex + 1, 0, m_Contents.Length - 1);
                else if (-offset.x > m_ViewBounds.extents.x)
                    m_ContentIndex = Mathf.Clamp(m_ContentIndex - 1, 0, m_Contents.Length - 1);
            }

            if (Vertical)
            {
                if (-offset.y > m_ViewBounds.extents.y)
                    m_ContentIndex = Mathf.Clamp(m_ContentIndex + 1, 0, m_Contents.Length - 1);
                else if (offset.y > m_ViewBounds.extents.y)
                    m_ContentIndex = Mathf.Clamp(m_ContentIndex - 1, 0, m_Contents.Length - 1);
            }
        }

        protected void SetDirty()
        {
            if (!IsActive())
                return;
            LayoutRebuilder.MarkLayoutForRebuild(RectTransform);
        }

        protected void SetDirtyCaching()
        {
            if (!IsActive())
                return;

            CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
            LayoutRebuilder.MarkLayoutForRebuild(RectTransform);
        }

#if UNITY_EDITOR
        protected override void OnValidate()
        {
            SetDirtyCaching();
        }
#endif
    }
}

你可能感兴趣的:(c#,开发语言,unity)