namespace UIWidgets { using System; using EasyLayoutNS; using UIWidgets.Attributes; using UnityEngine; using UnityEngine.Serialization; using UnityEngine.UI; /// /// ScrollRectBlock. /// public abstract class ScrollRectBlock : MonoBehaviourConditional { /// /// ScrollRect. /// [SerializeField] protected ScrollRect ScrollRect; /// /// Header. /// [SerializeField] [FormerlySerializedAs("Header")] protected RectTransform Block; /// /// Is ScrollRect has horizontal direction. /// [SerializeField] public bool IsHorizontal = false; /// /// Display type. /// [SerializeField] [FormerlySerializedAs("HeaderType")] protected ScrollRectHeaderType DisplayType = ScrollRectHeaderType.Reveal; /// /// Min size of the header. /// [SerializeField] [FormerlySerializedAs("HeaderMinSize")] [EditorConditionEnum("DisplayType", new int[] { (int)ScrollRectHeaderType.Resize })] public float MinSize = 30f; /// /// Last position of the ScrollRect.content. /// [NonSerialized] protected Vector2 LastPosition; /// /// Header size. /// [NonSerialized] protected Vector2 MaxSize; /// /// Layout. /// [NonSerialized] protected EasyLayout Layout; /// /// Layout margin delta. /// [NonSerialized] protected float MarginDelta; /// /// ScrollRect transform. /// [NonSerialized] protected RectTransform ScrollRectTransform; [NonSerialized] bool isInited; /// /// Start this instance. /// protected virtual void Start() { Init(); } /// /// Init this instance. /// public virtual void Init() { if (isInited) { return; } isInited = true; if ((ScrollRect != null) && (Block != null)) { ScrollRect.onValueChanged.AddListener(Scroll); ScrollRectTransform = ScrollRect.transform as RectTransform; LastPosition = GetPosition(); MaxSize = Block.rect.size; Layout = ScrollRect.content.GetComponent(); InitReveal(); InitLayout(); Scroll(Vector2.zero); } } /// /// Init for reveal display type. /// protected abstract void InitReveal(); /// /// Init layout. /// protected abstract void InitLayout(); /// /// Update layout. /// /// Size. protected abstract void UpdateLayout(float size); /// /// Get position. /// /// position. protected virtual Vector2 GetPosition() { return ScrollRect.content.anchoredPosition; } /// /// Process ScrollRect.onValueChanged event. /// /// ScrollRect value. protected void Scroll(Vector2 scrollPosition) { var position = GetPosition(); switch (DisplayType) { case ScrollRectHeaderType.Resize: Resize(position); break; case ScrollRectHeaderType.Reveal: Reveal(position); break; default: throw new NotSupportedException(string.Format("Unknown ScrollRectHeaderType: {0}", EnumHelper.ToString(DisplayType))); } LastPosition = position; } /// /// Get visible rate. /// /// Scroll position. /// Visible rate. protected float VisibleRate(Vector2 scrollPosition) { var scroll = IsHorizontal ? -scrollPosition.x : scrollPosition.y; var size = IsHorizontal ? MaxSize.x : MaxSize.y; var visible_rate = 1f - Mathf.Clamp01(scroll / size); return visible_rate; } /// /// Get reveal position. /// /// Visible rate. /// Position. protected abstract float RevealPosition(float rate); /// /// Reveal header. /// /// Current scroll position. protected void Reveal(Vector2 scrollPosition) { var current_pos = Block.anchoredPosition; var visible_rate = VisibleRate(scrollPosition); if (IsHorizontal) { current_pos.x = RevealPosition(visible_rate); } else { current_pos.y = RevealPosition(visible_rate); } Block.anchoredPosition = current_pos; var new_size = (IsHorizontal ? MaxSize.x : MaxSize.y) * visible_rate; UpdateLayout(new_size); } /// /// Resize header. /// /// Current ScrollRect.content position. protected void Resize(Vector2 scrollPosition) { var visible_rate = VisibleRate(scrollPosition); var new_size = Mathf.Lerp(MinSize, IsHorizontal ? MaxSize.x : MaxSize.y, visible_rate); var axis = IsHorizontal ? RectTransform.Axis.Horizontal : RectTransform.Axis.Vertical; Block.SetSizeWithCurrentAnchors(axis, new_size); UpdateLayout(new_size); } /// /// Destroy this instance. /// protected virtual void OnDestroy() { if (ScrollRect != null) { ScrollRect.onValueChanged.RemoveListener(Scroll); } } } }