• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
~Joke_crazy
爱生活,爱拉芳!
   首页    新随笔       管理     

循环滚动

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

namespace UnityEngine.UI
{
    public class LoopScroll : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
    {
        enum DragMode
        {
            None,
            Horizontal,
            Vertical,
        }

        public Action<int> callBack;
        [SerializeField]
        private DragMode mode;
        [SerializeField]
        public Transform content;
        [SerializeField, Tooltip("拖拽速度"), Range(1, 100f)]
        private float speed = 1;
        [SerializeField, Tooltip("居中速度"), Range(1, 20f)]
        private float ratio = 1;
        [SerializeField, Tooltip("滑动力度"), Range(10, 1000)]
        private float spring = 30;
        [SerializeField, Tooltip("显示间隔(s)"), Range(1, 60)]
        private float interval = 3;
        [SerializeField, Tooltip("自动显示")]
        private bool auto;
        [SerializeField]
        private Vector2 center;

        private Vector2 space;

        private Vector2 cell;

        private Vector2 vector;

        private float offset;

        private Vector2 position;

        private Vector2 point_begin;

        private Vector2 point_end;

        private int index_pre;

        private int index_target;

        private float spring_value;

        private int spring_offset;

        private bool center_state;

        private float center_ratio;

        private Vector2 center_vector;

        private Vector2 center_position;

        private float auto_timer;

        private bool m_drag;

        private readonly List<RectTransform> m_childs = new List<RectTransform>();

        private void Awake()
        {
            FormatPosition();
        }

        private void Update()
        {
            if (!m_drag && center_state)
            {
                center_ratio += Time.deltaTime * ratio;
                center_position = Vector2.Lerp(m_childs[index_target].localPosition, center, center_ratio);
                center_vector = center_position - (Vector2)m_childs[index_target].localPosition;

                Drag(center_vector);

                if (center_ratio > 1)
                {
                    center_state = false;
                }
            }

            if (auto)
            {
                if (m_drag)
                    auto_timer = 0;
                else
                    auto_timer += Time.deltaTime;

                if (auto_timer >= interval)
                {
                    auto_timer = 0;

                    Next();
                }
            }
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            if (Lock) return;

            point_begin = Input.mousePosition;

            m_drag = true;
        }

        public void OnDrag(PointerEventData eventData)
        {
            if (m_drag)
            {
                Drag(eventData.delta * speed * Time.deltaTime);
            }
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            if (Lock) return;

            point_end = Input.mousePosition;

            m_drag = false;

            index_target = -1;

            for (int i = 0; i < m_childs.Count; i++)
            {
                if (Center(m_childs[i].localPosition))
                {
                    index_target = i;
                    break;
                }
            }

            if (index_target != -1)
            {
                if (index_target == index_pre)
                {
                    switch (mode)
                    {
                        case DragMode.Horizontal:
                            spring_value = point_end.x - point_begin.x;
                            break;
                        case DragMode.Vertical:
                            spring_value = point_end.y - point_begin.y;
                            break;
                    }

                    if (Math.Abs(spring_value) > spring)
                    {
                        spring_offset = spring_value > 0 ? -1 : 1;

                        index_target += spring_offset;

                        if (index_target < 0)
                        {
                            index_target += m_childs.Count;
                        }
                        else if (index_target >= m_childs.Count)
                        {
                            index_target %= m_childs.Count;
                        }
                    }
                }

                index_pre = index_target;

                callBack?.Invoke(index_target);
            }

            center_ratio = 0;
            center_state = index_target != -1;
        }

        public void FormatPosition()
        {
            m_childs.Clear();

            Content _content = content.GetComponent<Content>();

            cell.x = _content.Horizontal;
            cell.y = _content.Vertical;

            for (int i = 0; i < content.childCount; i++)
            {
                if (content.GetChild(i).gameObject.activeSelf)
                {
                    m_childs.Add(content.GetChild(i) as RectTransform);
                }
            }

            Vector2 _position = center;

            for (int i = 0; i < m_childs.Count; i++)
            {
                m_childs[i].anchorMin = Vector2.one * 0.5f;
                m_childs[i].anchorMax = Vector2.one * 0.5f;
                m_childs[i].pivot = Vector2.one * 0.5f;
                m_childs[i].anchoredPosition = _position;

                _content.Adapt(m_childs[i]);

                switch (mode)
                {
                    case DragMode.Horizontal:
                        _position.x += cell.x;
                        break;
                    case DragMode.Vertical:
                        _position.y -= cell.y;
                        break;
                    default:
                        _position += cell;
                        break;
                }
            }

            int preview_index = 2;

            if (m_childs.Count > 0)
            {
                switch (mode)
                {
                    case DragMode.Horizontal:
                        space.x = m_childs[0].localPosition.x - preview_index * cell.x;
                        space.y = m_childs[m_childs.Count - preview_index].localPosition.x;
                        break;
                    case DragMode.Vertical:
                        space.x = m_childs[m_childs.Count - preview_index].localPosition.y;
                        space.y = m_childs[0].localPosition.y + preview_index * cell.y;
                        break;
                }
            }
            else
            {
                space = Vector2.zero;
            }
        }

        public void Jump(int index)
        {
            if (index < 0 || index >= m_childs.Count)
                return;

            index_pre = index_target = index;

            Drag(Vector2.one * -1);

            if (index_target != -1)
            {
                callBack?.Invoke(index_target);
            }

            center_ratio = 0;
            center_state = index_target != -1;
        }

        public bool Lock { get; set; }

        private void Next()
        {
            if (m_childs.Count == 0) return;

            index_target++;

            if (index_target >= m_childs.Count)
            {
                index_target %= m_childs.Count;
            }
            index_pre = index_target;

            Drag(Vector2.one * -1);

            if (index_target != -1)
            {
                callBack?.Invoke(index_target);
            }

            center_ratio = 0;
            center_state = index_target != -1;
        }

        private void Drag(Vector2 delta)
        {
            switch (mode)
            {
                case DragMode.Horizontal:
                    vector.x = delta.x;
                    vector.y = 0;
                    break;
                case DragMode.Vertical:
                    vector.x = 0;
                    vector.y = delta.y;
                    break;
                default:
                    vector = delta;
                    break;
            }

            for (int i = 0; i < m_childs.Count; i++)
            {
                position = m_childs[i].localPosition;
                position += vector;

                switch (mode)
                {
                    case DragMode.Horizontal:
                        if (position.x > space.y)
                        {
                            offset = position.x - space.y;
                            position.x = space.x + offset;
                        }
                        else if (position.x < space.x)
                        {
                            offset = position.x - space.x;
                            position.x = space.y + offset;
                        }
                        break;
                    case DragMode.Vertical:
                        if (position.y > space.y)
                        {
                            offset = position.y - space.y;
                            position.y = space.x + offset;
                        }
                        else if (position.y < space.x)
                        {
                            offset = position.y - space.x;
                            position.y = space.y + offset;
                        }
                        break;
                    default:
                        break;
                }

                m_childs[i].localPosition = position;
            }
        }

        private bool Center(Vector2 position)
        {
            bool result = false;

            switch (mode)
            {
                case DragMode.Horizontal:
                    result = Math.Abs(position.x - center.x) < cell.x / 2;
                    break;
                case DragMode.Vertical:
                    result = Math.Abs(position.y - center.y) < cell.y / 2;
                    break;
            }

            return result;
        }
    }
}
LoopScroll
using System.Collections.Generic;

namespace UnityEngine.UI
{
    [ExecuteInEditMode]
    public class Content : MonoBehaviour
    {
        private enum Axis
        {
            Horiaontal,
            Vertical,
        }

        private enum Stretch
        {
            None,
            Horiaontal,
            Vertical,
            Full,
        }

        [SerializeField] private Axis axis = Axis.Horiaontal;
        [SerializeField] private Stretch stretch = Stretch.None;
        [SerializeField] private RectTransform anchor = null;
        [SerializeField] private Vector2 size = new Vector2(100, 100);
        [SerializeField] private Vector2 spacing = Vector2.zero;
        [SerializeField] private bool adapt = false;

        private RectTransform m_target;

        private Vector2 m_position;

        private readonly List<RectTransform> m_childs = new List<RectTransform>();

        private void Awake()
        {
            m_target = GetComponent<RectTransform>();

            UpdateStretch();
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            if (m_target == null) return;

            UpdateStretch();

            m_childs.Clear();

            for (int i = 0; i < m_target.childCount; i++)
            {
                if (m_target.GetChild(i).gameObject.activeSelf)
                {
                    m_childs.Add(m_target.GetChild(i) as RectTransform);
                }
            }

            RefreshUI();
        }
#endif

        private void RefreshUI()
        {
            m_position = Vector2.zero;

            for (int i = 0; i < m_childs.Count; i++)
            {
                m_childs[i].anchoredPosition = m_position;

                Adapt(m_childs[i]);

                switch (axis)
                {
                    case Axis.Horiaontal:
                        m_position.x += Horizontal;
                        break;
                    case Axis.Vertical:
                        m_position.y -= Vertical;
                        break;
                }
            }
        }

        public void UpdateStretch()
        {
            switch (stretch)
            {
                case Stretch.Horiaontal:
                    size.x = anchor != null ? anchor.rect.width : m_target.rect.width;
                    break;
                case Stretch.Vertical:
                    size.y = anchor != null ? anchor.rect.height : m_target.rect.height;
                    break;
                case Stretch.Full:
                    size.x = anchor != null ? anchor.rect.width : m_target.rect.width;
                    size.y = anchor != null ? anchor.rect.height : m_target.rect.height;
                    break;
            }
        }

        public void Adapt(RectTransform rect)
        {
            if (adapt)
            {
                rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, Horizontal);
                rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, Vertical);
            }
        }

        public float Horizontal { get { return size.x + spacing.x; } }

        public float Vertical { get { return size.y + spacing.y; } }
    }
}
Content

注册:scroll.callBack = (index)=>{...};

使用:scroll.Jump(index);

需要展示的子节点物体需>=3,结构类似Scroll Rect,不需要加Fitter

 

posted @ 2020-03-27 16:03  ~Joke_crazy  阅读(232)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3