| //-------------------------------------------------------- | 
| //    [Author]:           玩个游戏 | 
| //    [  Date ]:           Monday, September 11, 2017 | 
| //-------------------------------------------------------- | 
| using UnityEngine; | 
| using System.Collections; | 
| using UnityEngine.UI; | 
| using UnityEngine.EventSystems; | 
| using System; | 
|   | 
| public class FlipScroll : MaskableGraphic, IBeginDragHandler, IEndDragHandler, IDragHandler | 
| { | 
|     public enum FlipDirEnum | 
|     { | 
|         Horizon, | 
|         Vertical, | 
|     } | 
|     private int page = 0; | 
|     /// <summary> | 
|     /// 当前页 | 
|     /// </summary> | 
|     public int Page { | 
|         get { return page; } | 
|     } | 
|     [SerializeField] | 
|     private FlipDirEnum flipType = FlipDirEnum.Horizon; | 
|     public FlipDirEnum FlipType { | 
|         get { | 
|             return flipType; | 
|         } | 
|         set { | 
|             flipType = value; | 
|         } | 
|     } | 
|     [SerializeField] | 
|     private bool m_Loop = false; | 
|     public bool loop { | 
|         get { | 
|             return m_Loop; | 
|         } | 
|         set { | 
|             m_Loop = value; | 
|         } | 
|     } | 
|   | 
|     [SerializeField] | 
|     private TweenType _tweenType = TweenType.Linear; | 
|     public TweenType tweenType { | 
|         get { return _tweenType; } | 
|         set { _tweenType = value; } | 
|     } | 
|     [SerializeField] | 
|     private float sensitive = 5.0f; | 
|   | 
|     public float Sensitive { | 
|         get { return sensitive; } | 
|         set { sensitive = value; } | 
|     } | 
|     [SerializeField] | 
|     public bool resetOnEnable = true; | 
|   | 
|     private bool tweening = false; | 
|     public bool IsTweening { get { return tweening; } } | 
|     [SerializeField] | 
|     private float _tweenTime = 1.0f; | 
|     public float TweenTime { | 
|         get { return _tweenTime; } | 
|         set { _tweenTime = value; } | 
|     } | 
|   | 
|     public RectTransform presentRT; | 
|     public RectTransform lastRT; | 
|   | 
|     private RectTransform presentFlipRT; | 
|     private RectTransform lastFlipRT; | 
|   | 
|     public event Action<int, RectTransform> OnRefreshData; | 
|     public event Action OnTweenCompt; | 
|   | 
|     public int pageCnt = 0; | 
|     [HideInInspector] | 
|     public bool locked = false; | 
|   | 
|     protected override void Awake() | 
|     { | 
|         base.Awake(); | 
|         if (presentRT == null || lastRT == null) return; | 
|         presentRT.SetActive(false); | 
|         lastRT.SetActive(false); | 
|         presentFlipRT = presentRT; | 
|         lastFlipRT = lastRT; | 
|     } | 
|   | 
|     protected override void OnEnable() | 
|     { | 
|         base.OnEnable(); | 
|         if (presentRT == null || lastRT == null || pageCnt == 0) return; | 
|         presentRT.SetActive(true); | 
|         lastRT.SetActive(true); | 
|         presentRT.localPosition = Vector3.zero; | 
|         if (resetOnEnable) { | 
|             switch (FlipType) { | 
|                 case FlipDirEnum.Horizon: | 
|                     lastRT.localPosition = rectTransform.localPosition.SetX(rectTransform.sizeDelta.x); | 
|                     break; | 
|                 case FlipDirEnum.Vertical: | 
|                     lastRT.localPosition = rectTransform.localPosition.SetY(-rectTransform.sizeDelta.y); | 
|                     break; | 
|             } | 
|             page = 0; | 
|         } | 
|         presentFlipRT = presentRT; | 
|         lastFlipRT = lastRT; | 
|         RefreshActive(); | 
|     } | 
|   | 
|     private Vector2 lastPos = Vector2.zero; | 
|     public void OnBeginDrag(PointerEventData eventData) | 
|     { | 
|         lastPos = eventData.position; | 
|     } | 
|   | 
|     public void OnEndDrag(PointerEventData eventData) | 
|     { | 
|         if (IsTweening || locked) return; | 
|         Vector2 nPos = lastPos - eventData.position; | 
|         switch (FlipType) { | 
|             case FlipDirEnum.Horizon: { | 
|                     if (Math.Abs(nPos.x) < sensitive) return; | 
|                     if (nPos.x > 0) { | 
|                         FlipRight(); | 
|                     } | 
|                     else { | 
|                         FlipLeft(); | 
|                     } | 
|                 } | 
|                 break; | 
|             case FlipDirEnum.Vertical: { | 
|                     if (Math.Abs(nPos.y) < sensitive) return; | 
|                     Vector3 pos = Vector3.zero; | 
|                     if (nPos.y < 0) { | 
|                         FlipLeft(); | 
|                     } | 
|                     else { | 
|                         FlipRight(); | 
|                     } | 
|                 } | 
|                 break; | 
|         } | 
|     } | 
|   | 
|     protected override void OnDisable() | 
|     { | 
|         tweening = false; | 
|         StopAllCoroutines(); | 
|         base.OnDisable(); | 
|     } | 
|   | 
|   | 
|   | 
|   | 
|     IEnumerator TweenPosition(Vector3 lPos, Vector3 nPos, Vector3 lastRtPos) | 
|     { | 
|         float time = 0; | 
|         Vector3 newPresentPos = Vector3.zero; | 
|         Vector3 newLastPos = Vector3.zero; | 
|         bool InView = false; | 
|         tweening = true; | 
|         while (time < _tweenTime) { | 
|             float per = 0; | 
|             switch (tweenType) { | 
|                 case TweenType.Immediate: per = 1; break; | 
|                 case TweenType.Linear: per = Linear(time / _tweenTime); break; | 
|                 case TweenType.Smooth: per = Smooth(time / _tweenTime); break; | 
|             } | 
|             newPresentPos = Vector3.Lerp(lPos, nPos, per); | 
|             newLastPos = Vector3.Lerp(lastRtPos, Vector3.zero, per); | 
|             presentFlipRT.localPosition = newPresentPos; | 
|             lastFlipRT.localPosition = newLastPos; | 
|             time += Time.unscaledDeltaTime; | 
|             if (!InView) { | 
|                 InView = InViewSide(); | 
|             } | 
|             if (tweenType == TweenType.Immediate) { | 
|                 break; | 
|             } | 
|             yield return null; | 
|         } | 
|         tweening = false; | 
|         presentFlipRT.localPosition = nPos; | 
|         lastFlipRT.localPosition = Vector3.zero; | 
|         RectTransform temp = presentFlipRT; | 
|         presentFlipRT = lastFlipRT; | 
|         lastFlipRT = temp; | 
|         if (OnTweenCompt != null) OnTweenCompt(); | 
|     } | 
|   | 
|     public bool InViewSide() | 
|     { | 
|         switch (FlipType) { | 
|             case FlipDirEnum.Horizon: { | 
|                     if (Vector3.Distance(Vector3.zero, lastFlipRT.localPosition) < lastFlipRT.sizeDelta.x + rectTransform.sizeDelta.x) { | 
|                         if (OnRefreshData != null) { | 
|                             lastFlipRT.SetActive(true); | 
|                             OnRefreshData(page, lastFlipRT); | 
|                         } | 
|                         return true; | 
|                     } | 
|                 } | 
|                 break; | 
|             case FlipDirEnum.Vertical: { | 
|                     if (Vector3.Distance(Vector3.zero, lastFlipRT.localPosition) < lastFlipRT.sizeDelta.y + rectTransform.sizeDelta.y) { | 
|                         if (OnRefreshData != null) { | 
|                             lastFlipRT.SetActive(true); | 
|                             OnRefreshData(page, lastFlipRT); | 
|                         } | 
|                         return true; | 
|                     } | 
|                 } | 
|                 break; | 
|         } | 
|         return false; | 
|     } | 
|   | 
|     private float Linear(float val) | 
|     { | 
|         return Mathf.Lerp(0, 1, val); | 
|     } | 
|   | 
|     private float Smooth(float val) | 
|     { | 
|         float result = Mathf.SmoothStep(0, 1, val); | 
|         result = Mathf.Clamp(result, 0, 1); | 
|         return result; | 
|     } | 
|   | 
|     public void RefreshActive() | 
|     { | 
|         if (pageCnt == 0 || presentFlipRT == null) return; | 
|         if (OnRefreshData != null) { | 
|             presentFlipRT.SetActive(true); | 
|             OnRefreshData(page, presentFlipRT); | 
|         } | 
|     } | 
|   | 
|     public void FlipLeft() | 
|     { | 
|         if (IsTweening || pageCnt == 0) return; | 
|         Vector3 pos = Vector3.zero; | 
|         page--; | 
|         if (page < 0) { | 
|             if (loop) { | 
|                 page = pageCnt - 1; | 
|             } | 
|             else { | 
|                 page = 0; | 
|                 return; | 
|             } | 
|         } | 
|         switch (FlipType) { | 
|             case FlipDirEnum.Horizon: { | 
|                     lastFlipRT.localPosition = rectTransform.localPosition.SetX(-rectTransform.sizeDelta.x); | 
|                     pos = rectTransform.localPosition.SetX(rectTransform.sizeDelta.x); | 
|                 } | 
|                 break; | 
|             case FlipDirEnum.Vertical: { | 
|                     lastFlipRT.localPosition = rectTransform.localPosition.SetY(rectTransform.sizeDelta.y); | 
|                     pos = rectTransform.localPosition.SetY(-rectTransform.sizeDelta.y); | 
|                 } | 
|                 break; | 
|         } | 
|         StartCoroutine(TweenPosition(presentFlipRT.localPosition, pos, lastFlipRT.localPosition)); | 
|     } | 
|   | 
|     public void FlipRight() | 
|     { | 
|         if (IsTweening || pageCnt == 0) return; | 
|         Vector3 pos = Vector3.zero; | 
|         page++; | 
|         if (page >= pageCnt) { | 
|             if (loop) { | 
|                 page = 0; | 
|             } | 
|             else { | 
|                 page = pageCnt - 1; | 
|                 return; | 
|             } | 
|         } | 
|         switch (FlipType) { | 
|             case FlipDirEnum.Horizon: { | 
|                     lastFlipRT.localPosition = rectTransform.localPosition.SetX(rectTransform.sizeDelta.x); | 
|                     pos = rectTransform.localPosition.SetX(-rectTransform.sizeDelta.x); | 
|                 } | 
|                 break; | 
|             case FlipDirEnum.Vertical: { | 
|                     lastFlipRT.localPosition = rectTransform.localPosition.SetY(-rectTransform.sizeDelta.y); | 
|                     pos = rectTransform.localPosition.SetY(rectTransform.sizeDelta.y); | 
|                 } | 
|                 break; | 
|         } | 
|         StartCoroutine(TweenPosition(presentFlipRT.localPosition, pos, lastFlipRT.localPosition)); | 
|     } | 
|   | 
|     public void OnDrag(PointerEventData eventData) | 
|     { | 
|   | 
|     } | 
|   | 
|     public enum TweenType | 
|     { | 
|         Immediate, | 
|         Linear, | 
|         Smooth, | 
|     } | 
| } |