ugui模仿 - ScrollBar
效果
这边只实现了滚动条的核心逻辑:
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方向的没做