using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; [Serializable] public sealed class PageChangedEvent : UnityEvent {} public class PageScrollRect : ScrollRect, IPointerDownHandler { [SerializeField] private float duration = 0.2f; [SerializeField] private Button prevButton = default; [SerializeField] private Button nextButton = default; [SerializeField] private PageChangedEvent onPageChanged = default; public PageChangedEvent OnPageChanged { get{ return onPageChanged; } } private float pageWidth; private int prevPageIndex = 0; private int prevPageIndexLate = 0; private Coroutine coroutine; protected override void Awake(){ base.Awake(); var grid = content.GetComponent(); pageWidth = grid.cellSize.x + grid.spacing.x; if(prevButton){ prevButton.gameObject.SetActive(prevPageIndex > 0); prevButton.onClick.AddListener(() => ChangePage(prevPageIndexLate - 1)); } if(nextButton){ nextButton.onClick.AddListener(() => ChangePage(prevPageIndexLate + 1)); } } public override void OnBeginDrag(PointerEventData eventData){ base.OnBeginDrag(eventData); } public override void OnEndDrag(PointerEventData eventData){ base.OnEndDrag(eventData); // 慣性を停止 StopMovement(); var pageIndex = -Mathf.RoundToInt(content.anchoredPosition.x / pageWidth); // ページが変わっていない且つ素早くドラッグした場合 if(pageIndex == prevPageIndex && Mathf.Abs(eventData.delta.x) >= 5){ pageIndex -= (int)Mathf.Sign(eventData.delta.x); } ChangePage(pageIndex); } private void ChangePage(int pageIndex){ var maxPage = content.childCount - 1; pageIndex = Mathf.Clamp(pageIndex, 0, maxPage); var destX = -pageIndex * pageWidth; if(content.anchoredPosition.x != destX){ this.SafeStopCoroutine(coroutine); var from = content.anchoredPosition.x; coroutine = this.CallLerpRealtime(duration * Mathf.Abs(from - destX) / pageWidth, t => { content.anchoredPosition = content.anchoredPosition.SetX(Mathf.Lerp(from, destX, t * t)); }, () => { prevPageIndexLate = pageIndex; if(prevButton){ prevButton.gameObject.SetActive(pageIndex > 0); } if(nextButton){ nextButton.gameObject.SetActive(pageIndex < maxPage); } onPageChanged.Invoke(pageIndex); }); } prevPageIndex = pageIndex; } public void ImmediateChangePage(int pageIndex){ var maxPage = content.childCount - 1; pageIndex = Mathf.Clamp(pageIndex, 0, maxPage); var destX = -pageIndex * pageWidth; if(content.anchoredPosition.x != destX){ this.SafeStopCoroutine(coroutine); content.anchoredPosition = content.anchoredPosition.SetX(destX); } if(prevButton){ prevButton.gameObject.SetActive(pageIndex > 0); } if(nextButton){ nextButton.gameObject.SetActive(pageIndex < maxPage); } prevPageIndex = pageIndex; prevPageIndexLate = pageIndex; } public void OnPointerDown(PointerEventData eventData){ this.SafeStopCoroutine(coroutine); } }