ugui模仿 - ScrollBar

发布时间 2023-08-31 00:13:19作者: yanghui01

效果

 

这边只实现了滚动条的核心逻辑:

1) 点下时, 点在滑动轨道空白区域, 滑动块直接滚动到点击位置(这边是直接瞬时滚动了, 可以优化成动画滚动)

2) 点下时, 点在滑动块上, 可以拖动滑动块进行滚动

using UnityEngine;
using UnityEngine.EventSystems;

[DisallowMultipleComponent]
[RequireComponent(typeof(RectTransform))]
public class MyScrollBar : UIBehaviour
    , IPointerDownHandler, IInitializePotentialDragHandler, IBeginDragHandler, IDragHandler
{

    // 滑动块
    public RectTransform m_HandleRect;

    // 滑动区域
    public RectTransform m_TrackRect;

    private float m_ScrollPercent;

    // 滑动块大小, 值为滑动区域的百分比
    private float m_HandleSize = 0.2f;

    private bool m_IsDragHandle;
    // 开始拖动前的指针坐标(以滑动轨道pivot为原点)
    private Vector2 m_PointerPosOnBeginDrag;
    private float m_ScrollPercentOnBeginDrag = 0;

    public float scrollPercent
    {
        get { return m_ScrollPercent; }
        set
        {
            SetScrollPercent(value);
        }
    }

    public float handleSize
    {
        get { return m_HandleSize; }
        set
        {
            if (m_HandleSize != value)
            {
                m_HandleSize = value;
                UpdateHandleAnchorArea();
            }
        }
    }

    public void SetScrollPercent(float scrollPercent)
    {
        scrollPercent = Mathf.Clamp01(scrollPercent);
        if (m_ScrollPercent == scrollPercent) return;

        m_ScrollPercent = scrollPercent;

        UpdateHandleAnchorArea();
    }

    private void UpdateHandleAnchorArea()
    {
        var anchorMin = Vector2.zero;
        var anchorMax = Vector2.one;

        float scrollTrackPercent = 1 - m_HandleSize;
        //比如: 滚动50%时, 滑动块center在0.5处, 滑动块左侧在0.5-m_Size/2, 把scrollPercent代入: (1-m_Size)*50%
        anchorMin.x = scrollTrackPercent * m_ScrollPercent;
        anchorMax.x = anchorMin.x + m_HandleSize;

        m_HandleRect.anchorMin = anchorMin;
        m_HandleRect.anchorMax = anchorMax;
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        //没有点在滑块上, 点在滑动区域空白处
        if (!RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
        {
            Vector2 localCursor;
            bool isLocalCursorValid = RectTransformUtility.ScreenPointToLocalPointInRectangle(m_TrackRect, eventData.position, eventData.pressEventCamera, out localCursor);
            if (!isLocalCursorValid)
                return;

            float maxScrollSize = m_TrackRect.rect.width * (1 - m_HandleSize);
            if (maxScrollSize > 0)
            {
                var scrollDistance = localCursor - m_TrackRect.rect.position;
                SetScrollPercent(scrollDistance.x / maxScrollSize - m_HandleSize * 0.5f);
            }
        }
    }

    public void OnInitializePotentialDrag(PointerEventData eventData)
    {
        eventData.useDragThreshold = false;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        m_IsDragHandle = false;
        if (RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
        {
            Vector2 localCursor;
            bool isLocalCursorValid = RectTransformUtility.ScreenPointToLocalPointInRectangle(m_TrackRect, eventData.position, eventData.pressEventCamera, out localCursor);
            if (isLocalCursorValid)
            {
                m_IsDragHandle = true;
                m_PointerPosOnBeginDrag = localCursor;
                m_ScrollPercentOnBeginDrag = m_ScrollPercent;
            }
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        //点在滑块上拖动
        if (m_IsDragHandle)
        {
            Vector2 localCursor;
            bool isLocalCursorValid = RectTransformUtility.ScreenPointToLocalPointInRectangle(m_TrackRect, eventData.position, eventData.pressEventCamera, out localCursor);
            if (!isLocalCursorValid)
                return;

            float maxScrollSize = m_TrackRect.rect.width * (1 - m_HandleSize);
            if (maxScrollSize > 0)
            {
                var dragDistance = localCursor - m_PointerPosOnBeginDrag;
                SetScrollPercent(m_ScrollPercentOnBeginDrag + (dragDistance.x / maxScrollSize));
            }
        }
    }

}

 

ugui ScrollBar做了,这边精简掉了的:

1) 用方向键滚动ScrollBar

2) 用鼠标滚轮滚动ScrollBar

3) 只做了LeftToRight方向的滚动条, RightToLeft、TopToBottom、BottomToTop方向的没做