/* * FancyScrollView (https://github.com/setchi/FancyScrollView) * Copyright (c) 2020 setchi * Licensed under MIT (https://github.com/setchi/FancyScrollView/blob/master/LICENSE) */ using System; using System.Collections.Generic; using UnityEngine; using EasingCore; namespace FancyScrollView { /// /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. /// /// Documentation text normalized. /// Documentation text normalized. [RequireComponent(typeof(Scroller))] public abstract class FancyScrollRect : FancyScrollView where TContext : class, IFancyScrollRectContext, new() { /// /// Documentation text normalized. /// /// /// Documentation text normalized. /// Documentation text normalized. /// [SerializeField] protected float reuseCellMarginCount = 0f; /// /// Documentation text normalized. /// [SerializeField] protected float paddingHead = 0f; /// /// Documentation text normalized. /// [SerializeField] protected float paddingTail = 0f; /// /// Documentation text normalized. /// [SerializeField] protected float spacing = 0f; /// /// Documentation text normalized. /// protected abstract float CellSize { get; } /// /// Documentation text normalized. /// /// /// Documentation text normalized. /// protected virtual bool Scrollable => MaxScrollPosition > 0f; Scroller cachedScroller; /// /// Documentation text normalized. /// /// /// Documentation text normalized. /// protected Scroller Scroller => cachedScroller ?? (cachedScroller = GetComponent()); float ScrollLength => 1f / Mathf.Max(cellInterval, 1e-2f) - 1f; float ViewportLength => ScrollLength - reuseCellMarginCount * 2f; float PaddingHeadLength => (paddingHead - spacing * 0.5f) / (CellSize + spacing); float MaxScrollPosition => ItemsSource.Count - ScrollLength + reuseCellMarginCount * 2f + (paddingHead + paddingTail - spacing) / (CellSize + spacing); /// protected override void Initialize() { base.Initialize(); Context.ScrollDirection = Scroller.ScrollDirection; Context.CalculateScrollSize = () => { var interval = CellSize + spacing; var reuseMargin = interval * reuseCellMarginCount; var scrollSize = Scroller.ViewportSize + interval + reuseMargin * 2f; return (scrollSize, reuseMargin); }; AdjustCellIntervalAndScrollOffset(); Scroller.OnValueChanged(OnScrollerValueChanged); } /// /// Documentation text normalized. /// /// Documentation text normalized. void OnScrollerValueChanged(float p) { base.UpdatePosition(ToFancyScrollViewPosition(Scrollable ? p : 0f)); if (Scroller.Scrollbar) { if (p > ItemsSource.Count - 1) { ShrinkScrollbar(p - (ItemsSource.Count - 1)); } else if (p < 0f) { ShrinkScrollbar(-p); } } } /// /// Documentation text normalized. /// /// Documentation text normalized. void ShrinkScrollbar(float offset) { var scale = 1f - ToFancyScrollViewPosition(offset) / (ViewportLength - PaddingHeadLength); UpdateScrollbarSize((ViewportLength - PaddingHeadLength) * scale); } /// protected override void Refresh() { AdjustCellIntervalAndScrollOffset(); RefreshScroller(); base.Refresh(); } /// protected override void Relayout() { AdjustCellIntervalAndScrollOffset(); RefreshScroller(); base.Relayout(); } /// /// Documentation text normalized. /// protected void RefreshScroller() { Scroller.Draggable = Scrollable; Scroller.ScrollSensitivity = ToScrollerPosition(ViewportLength - PaddingHeadLength); Scroller.Position = ToScrollerPosition(currentPosition); if (Scroller.Scrollbar) { Scroller.Scrollbar.gameObject.SetActive(Scrollable); UpdateScrollbarSize(ViewportLength); } } /// protected override void UpdateContents(IList items) { AdjustCellIntervalAndScrollOffset(); base.UpdateContents(items); Scroller.SetTotalCount(items.Count); RefreshScroller(); } /// /// Documentation text normalized. /// /// Documentation text normalized. protected new void UpdatePosition(float position) { Scroller.Position = ToScrollerPosition(position, 0.5f); } /// /// Documentation text normalized. /// /// Documentation text normalized. /// Documentation text normalized. protected virtual void JumpTo(int itemIndex, float alignment = 0.5f) { Scroller.Position = ToScrollerPosition(itemIndex, alignment); } /// /// Documentation text normalized. /// /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. protected virtual void ScrollTo(int index, float duration, float alignment = 0.5f, Action onComplete = null) { Scroller.ScrollTo(ToScrollerPosition(index, alignment), duration, onComplete); } /// /// Documentation text normalized. /// /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. protected virtual void ScrollTo(int index, float duration, Ease easing, float alignment = 0.5f, Action onComplete = null) { Scroller.ScrollTo(ToScrollerPosition(index, alignment), duration, easing, onComplete); } /// /// Documentation text normalized. /// /// Documentation text normalized. protected void UpdateScrollbarSize(float viewportLength) { var contentLength = Mathf.Max(ItemsSource.Count + (paddingHead + paddingTail - spacing) / (CellSize + spacing), 1); Scroller.Scrollbar.size = Scrollable ? Mathf.Clamp01(viewportLength / contentLength) : 1f; } /// /// Documentation text normalized. /// /// Documentation text normalized. /// Documentation text normalized. protected float ToFancyScrollViewPosition(float position) { return position / Mathf.Max(ItemsSource.Count - 1, 1) * MaxScrollPosition - PaddingHeadLength; } /// /// Documentation text normalized. /// /// Documentation text normalized. /// Documentation text normalized. protected float ToScrollerPosition(float position) { return (position + PaddingHeadLength) / MaxScrollPosition * Mathf.Max(ItemsSource.Count - 1, 1); } /// /// Documentation text normalized. /// /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. protected float ToScrollerPosition(float position, float alignment = 0.5f) { var offset = alignment * (ScrollLength - (1f + reuseCellMarginCount * 2f)) + (1f - alignment - 0.5f) * spacing / (CellSize + spacing); return ToScrollerPosition(Mathf.Clamp(position - offset, 0f, MaxScrollPosition)); } /// /// Documentation text normalized. /// Documentation text normalized. /// Documentation text normalized. /// protected void AdjustCellIntervalAndScrollOffset() { var totalSize = Scroller.ViewportSize + (CellSize + spacing) * (1f + reuseCellMarginCount * 2f); cellInterval = (CellSize + spacing) / totalSize; scrollOffset = cellInterval * (1f + reuseCellMarginCount); } protected virtual void OnValidate() { AdjustCellIntervalAndScrollOffset(); if (loop) { loop = false; Debug.LogError("Loop is currently not supported in FancyScrollRect."); } if (Scroller.SnapEnabled) { Scroller.SnapEnabled = false; Debug.LogError("Snap is currently not supported in FancyScrollRect."); } if (Scroller.MovementType == MovementType.Unrestricted) { Scroller.MovementType = MovementType.Elastic; Debug.LogError("MovementType.Unrestricted is currently not supported in FancyScrollRect."); } } } /// /// Documentation text normalized. /// Documentation text normalized. /// /// Documentation text normalized. /// public abstract class FancyScrollRect : FancyScrollRect { } }