popcorn/Scripts/UI/PageScrollRect.cs

107 lines
3.6 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[Serializable]
public sealed class PageChangedEvent : UnityEvent<int> {}
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<GridLayoutGroup>();
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);
}
}