| //-------------------------------------------------------- | 
| //    [Author]:           第二世界 | 
| //    [  Date ]:           Monday, September 11, 2017 | 
| //-------------------------------------------------------- | 
| using UnityEngine; | 
| using System.Collections; | 
| using UnityEngine.UI; | 
| using UnityEngine.EventSystems; | 
| using System; | 
| namespace vnxbqy.UI | 
| { | 
|     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, | 
|         } | 
|     } | 
| } |