临时提交
This commit is contained in:
parent
255892dd5f
commit
db11a4aa1a
@ -105,6 +105,26 @@ namespace AlicizaX.UI
|
||||
return -index;
|
||||
}
|
||||
|
||||
public override float GetItemStartPosition(int index)
|
||||
{
|
||||
return IndexToPosition(index);
|
||||
}
|
||||
|
||||
public override float GetItemLength(int index)
|
||||
{
|
||||
return Mathf.Abs(intervalAngle);
|
||||
}
|
||||
|
||||
public override int GetSnapIndex(float position)
|
||||
{
|
||||
if (adapter == null || adapter.GetItemCount() <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Clamp(PositionToIndex(position), 0, adapter.GetItemCount() - 1);
|
||||
}
|
||||
|
||||
public override void DoItemAnimation()
|
||||
{
|
||||
int visibleCount = viewProvider.VisibleCount;
|
||||
|
||||
@ -174,5 +174,50 @@ namespace AlicizaX.UI
|
||||
|
||||
return index * unit;
|
||||
}
|
||||
|
||||
public override float GetItemStartPosition(int index)
|
||||
{
|
||||
if (adapter == null || adapter.GetItemCount() <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
index = Mathf.Clamp(index, 0, adapter.GetItemCount() - 1);
|
||||
int row = index / unit;
|
||||
float len = direction == Direction.Vertical ? cellSize.y + spacing.y : cellSize.x + spacing.x;
|
||||
return row * len;
|
||||
}
|
||||
|
||||
public override float GetItemLength(int index)
|
||||
{
|
||||
return direction == Direction.Vertical ? Mathf.Max(cellSize.y, 0f) : Mathf.Max(cellSize.x, 0f);
|
||||
}
|
||||
|
||||
public override int GetSnapIndex(float position)
|
||||
{
|
||||
if (adapter == null || adapter.GetItemCount() <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float len = direction == Direction.Vertical ? cellSize.y + spacing.y : cellSize.x + spacing.x;
|
||||
float itemLength = GetItemLength(0);
|
||||
if (len <= 0f || itemLength <= 0f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int itemCount = adapter.GetItemCount();
|
||||
int row = Mathf.FloorToInt(Mathf.Max(position, 0f) / len);
|
||||
int index = Mathf.Clamp(row * unit, 0, itemCount - 1);
|
||||
|
||||
float visibleLength = itemLength - (position - GetItemStartPosition(index));
|
||||
if (visibleLength < itemLength * 0.5f && index + unit < itemCount)
|
||||
{
|
||||
index += unit;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,12 @@ namespace AlicizaX.UI
|
||||
|
||||
int PositionToIndex(float position);
|
||||
|
||||
float GetItemStartPosition(int index);
|
||||
|
||||
float GetItemLength(int index);
|
||||
|
||||
int GetSnapIndex(float position);
|
||||
|
||||
void DoItemAnimation();
|
||||
|
||||
bool IsFullVisibleStart(int index);
|
||||
|
||||
@ -142,6 +142,20 @@ namespace AlicizaX.UI
|
||||
|
||||
public abstract int PositionToIndex(float position);
|
||||
|
||||
public abstract float GetItemStartPosition(int index);
|
||||
|
||||
public abstract float GetItemLength(int index);
|
||||
|
||||
public virtual int GetSnapIndex(float position)
|
||||
{
|
||||
if (adapter == null || adapter.GetItemCount() <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Clamp(PositionToIndex(position), 0, adapter.GetItemCount() - 1);
|
||||
}
|
||||
|
||||
public virtual void DoItemAnimation() { }
|
||||
|
||||
public virtual bool IsFullVisibleStart(int index)
|
||||
|
||||
@ -143,5 +143,49 @@ namespace AlicizaX.UI
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public override float GetItemStartPosition(int index)
|
||||
{
|
||||
if (adapter == null || adapter.GetItemCount() <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
index = Mathf.Clamp(index, 0, adapter.GetItemCount() - 1);
|
||||
float len = direction == Direction.Vertical ? lineHeight + spacing.y : lineHeight + spacing.x;
|
||||
return index * len;
|
||||
}
|
||||
|
||||
public override float GetItemLength(int index)
|
||||
{
|
||||
return Mathf.Max(lineHeight, 0f);
|
||||
}
|
||||
|
||||
public override int GetSnapIndex(float position)
|
||||
{
|
||||
if (adapter == null || adapter.GetItemCount() <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float len = direction == Direction.Vertical ? lineHeight + spacing.y : lineHeight + spacing.x;
|
||||
float itemLength = GetItemLength(0);
|
||||
if (len <= 0f || itemLength <= 0f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int itemCount = adapter.GetItemCount();
|
||||
int index = Mathf.FloorToInt(Mathf.Max(position, 0f) / len);
|
||||
index = Mathf.Clamp(index, 0, itemCount - 1);
|
||||
|
||||
float visibleLength = itemLength - (position - GetItemStartPosition(index));
|
||||
if (visibleLength < itemLength * 0.5f && index < itemCount - 1)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,6 +145,62 @@ namespace AlicizaX.UI
|
||||
return index >= 0 ? index : cachedItemCount - 1;
|
||||
}
|
||||
|
||||
public override float GetItemStartPosition(int index)
|
||||
{
|
||||
EnsurePositionCache();
|
||||
if (cachedItemCount <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
index = Mathf.Clamp(index, 0, cachedItemCount - 1);
|
||||
return itemPositions[index];
|
||||
}
|
||||
|
||||
public override float GetItemLength(int index)
|
||||
{
|
||||
EnsurePositionCache();
|
||||
if (cachedItemCount <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
index = Mathf.Clamp(index, 0, cachedItemCount - 1);
|
||||
float spacingLength = index < cachedItemCount - 1
|
||||
? (direction == Direction.Vertical ? spacing.y : spacing.x)
|
||||
: 0f;
|
||||
return Mathf.Max(itemLengths[index] - spacingLength, 0f);
|
||||
}
|
||||
|
||||
public override int GetSnapIndex(float position)
|
||||
{
|
||||
EnsurePositionCache();
|
||||
if (cachedItemCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int index = FindFirstItemEndingAfter(Mathf.Max(position, 0f));
|
||||
if (index < 0)
|
||||
{
|
||||
return cachedItemCount - 1;
|
||||
}
|
||||
|
||||
float itemLength = GetItemLength(index);
|
||||
if (itemLength <= 0f)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
float visibleLength = itemLength - (position - GetItemStartPosition(index));
|
||||
if (visibleLength < itemLength * 0.5f && index < cachedItemCount - 1)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private void EnsurePositionCache()
|
||||
{
|
||||
int itemCount = adapter != null ? adapter.GetItemCount() : 0;
|
||||
|
||||
@ -1203,12 +1203,11 @@ namespace AlicizaX.UI
|
||||
return scroller.Position;
|
||||
}
|
||||
|
||||
float itemSize = GetItemSize(index);
|
||||
float itemSize = layoutManager.GetItemLength(index);
|
||||
float viewportLength = direction == Direction.Vertical ? layoutManager.ViewportSize.y : layoutManager.ViewportSize.x;
|
||||
float contentLength = direction == Direction.Vertical ? layoutManager.ContentSize.y : layoutManager.ContentSize.x;
|
||||
|
||||
// 计算目标项的原始位置,不在此阶段做范围限制<E99990>?
|
||||
float itemPosition = CalculateRawItemPosition(index);
|
||||
float itemPosition = layoutManager.GetItemStartPosition(index);
|
||||
|
||||
float targetPosition = alignment switch
|
||||
{
|
||||
@ -1276,13 +1275,7 @@ namespace AlicizaX.UI
|
||||
/// </summary>
|
||||
private void OnMoveStoped()
|
||||
{
|
||||
if (snap && SnapToNearestItem())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TryProcessPendingFocusRequest();
|
||||
OnScrollStopped?.Invoke();
|
||||
HandleScrollSettled();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1313,10 +1306,7 @@ namespace AlicizaX.UI
|
||||
{
|
||||
if (scroller == null) return;
|
||||
|
||||
if (scroller.Position < scroller.MaxPosition && snap)
|
||||
{
|
||||
SnapToNearestItem();
|
||||
}
|
||||
HandleScrollSettled();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -1603,17 +1593,36 @@ namespace AlicizaX.UI
|
||||
/// <returns>触发了新的吸附滚动时返回 <see langword="true"/>;否则返<E58899>?<see langword="false"/><3E>?/returns>
|
||||
private bool SnapToNearestItem()
|
||||
{
|
||||
int index = layoutManager.PositionToIndex(GetScrollPosition());
|
||||
float targetPosition = layoutManager.IndexToPosition(index);
|
||||
if (Mathf.Abs(targetPosition - GetScrollPosition()) <= 0.1f)
|
||||
if (layoutManager == null || RecyclerViewAdapter == null || RecyclerViewAdapter.GetItemCount() <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ScrollTo(index, true);
|
||||
float position = GetScrollPosition();
|
||||
int index = layoutManager.GetSnapIndex(position);
|
||||
index = Mathf.Clamp(index, 0, RecyclerViewAdapter.GetItemCount() - 1);
|
||||
float targetPosition = layoutManager.IndexToPosition(index);
|
||||
UpdateCurrentIndex(index);
|
||||
if (Mathf.Abs(targetPosition - position) <= 0.1f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
scroller.ScrollToDuration(targetPosition, 0.12f);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void HandleScrollSettled()
|
||||
{
|
||||
if (snap && SnapToNearestItem())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TryProcessPendingFocusRequest();
|
||||
OnScrollStopped?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新当前逻辑索引,并在变化时触发事件通知<E9809A>?
|
||||
/// </summary>
|
||||
|
||||
@ -55,8 +55,9 @@ namespace AlicizaX.UI
|
||||
return delta * 0.1f;
|
||||
}
|
||||
|
||||
protected override void Elastic()
|
||||
protected override bool StartElasticMotion()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,12 @@ namespace AlicizaX.UI
|
||||
{
|
||||
public class Scroller : MonoBehaviour, IScroller, IBeginDragHandler, IEndDragHandler, IDragHandler, IScrollHandler
|
||||
{
|
||||
private const float MaxInertiaVelocity = 60f;
|
||||
private const float MinInertiaDuration = 0.06f;
|
||||
private const float MaxInertiaDuration = 0.24f;
|
||||
private const float MinInertiaDistanceFactor = 1.5f;
|
||||
private const float MaxInertiaDistanceFactor = 6f;
|
||||
|
||||
protected enum MotionState
|
||||
{
|
||||
Idle,
|
||||
@ -83,6 +89,8 @@ namespace AlicizaX.UI
|
||||
private float motionDuration;
|
||||
private float motionSpeed;
|
||||
private float inertiaVelocity;
|
||||
private float inertiaDistance;
|
||||
private bool notifyMoveStoppedOnComplete;
|
||||
|
||||
public float MaxPosition => direction == Direction.Vertical ? Mathf.Max(contentSize.y - viewSize.y, 0) : Mathf.Max(contentSize.x - viewSize.x, 0);
|
||||
|
||||
@ -154,7 +162,7 @@ namespace AlicizaX.UI
|
||||
return;
|
||||
}
|
||||
|
||||
StartPositionMotion(position, scrollSpeed);
|
||||
StartPositionMotion(position, scrollSpeed, true);
|
||||
}
|
||||
|
||||
public virtual void ScrollToDuration(float position, float duration)
|
||||
@ -177,6 +185,7 @@ namespace AlicizaX.UI
|
||||
motionTargetPosition = position;
|
||||
motionDuration = Mathf.Max(duration, 0.0001f);
|
||||
motionElapsed = 0f;
|
||||
notifyMoveStoppedOnComplete = true;
|
||||
}
|
||||
|
||||
public virtual void ScrollToRatio(float ratio)
|
||||
@ -202,8 +211,7 @@ namespace AlicizaX.UI
|
||||
return;
|
||||
}
|
||||
|
||||
Inertia();
|
||||
Elastic();
|
||||
StartReleaseMotion();
|
||||
OnDragging?.Invoke(false);
|
||||
}
|
||||
|
||||
@ -234,8 +242,7 @@ namespace AlicizaX.UI
|
||||
position += velocity;
|
||||
|
||||
OnValueChanged?.Invoke(position);
|
||||
Inertia();
|
||||
Elastic();
|
||||
StartReleaseMotion();
|
||||
}
|
||||
|
||||
internal virtual float GetDelta(PointerEventData eventData)
|
||||
@ -277,36 +284,57 @@ namespace AlicizaX.UI
|
||||
motionState = MotionState.Inertia;
|
||||
motionStartPosition = position;
|
||||
motionElapsed = 0f;
|
||||
motionDuration = snap ? 0.1f : 1f;
|
||||
inertiaVelocity = velocity > 0 ? Mathf.Min(velocity, 100) : Mathf.Max(velocity, -100);
|
||||
inertiaVelocity = Mathf.Clamp(velocity, -MaxInertiaVelocity, MaxInertiaVelocity);
|
||||
float normalizedVelocity = Mathf.Clamp01(Mathf.Abs(inertiaVelocity) / MaxInertiaVelocity);
|
||||
motionDuration = Mathf.Lerp(MinInertiaDuration, MaxInertiaDuration, normalizedVelocity);
|
||||
float distanceFactor = Mathf.Lerp(MinInertiaDistanceFactor, MaxInertiaDistanceFactor, normalizedVelocity);
|
||||
inertiaDistance = inertiaVelocity * distanceFactor;
|
||||
notifyMoveStoppedOnComplete = true;
|
||||
}
|
||||
|
||||
protected virtual void Elastic()
|
||||
protected virtual bool StartElasticMotion()
|
||||
{
|
||||
if (position < 0)
|
||||
{
|
||||
StopMovement();
|
||||
StartPositionMotion(0, 7f);
|
||||
StartPositionMotion(0, 7f, true);
|
||||
return true;
|
||||
}
|
||||
else if (position > MaxPosition)
|
||||
|
||||
if (position > MaxPosition)
|
||||
{
|
||||
StopMovement();
|
||||
StartPositionMotion(MaxPosition, 7f);
|
||||
StartPositionMotion(MaxPosition, 7f, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void StopMovement()
|
||||
{
|
||||
motionState = MotionState.Idle;
|
||||
notifyMoveStoppedOnComplete = false;
|
||||
}
|
||||
|
||||
private void StartPositionMotion(float targetPosition, float speed)
|
||||
private void StartReleaseMotion()
|
||||
{
|
||||
if (StartElasticMotion())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Inertia();
|
||||
}
|
||||
|
||||
private void StartPositionMotion(float targetPosition, float speed, bool notifyStopped)
|
||||
{
|
||||
motionState = MotionState.Smooth;
|
||||
motionStartPosition = position;
|
||||
motionTargetPosition = targetPosition;
|
||||
motionElapsed = Time.deltaTime;
|
||||
motionSpeed = speed;
|
||||
notifyMoveStoppedOnComplete = notifyStopped;
|
||||
}
|
||||
|
||||
private void TickSmooth(float deltaTime)
|
||||
@ -343,8 +371,8 @@ namespace AlicizaX.UI
|
||||
{
|
||||
motionElapsed += deltaTime;
|
||||
float t = Mathf.Clamp01(motionElapsed / motionDuration);
|
||||
float y = (float)EaseUtil.EaseOutCirc(t) * 40f;
|
||||
float nextPosition = motionStartPosition + y * inertiaVelocity;
|
||||
float offset = (float)EaseUtil.EaseOutCirc(t) * inertiaDistance;
|
||||
float nextPosition = motionStartPosition + offset;
|
||||
float maxPosition = MaxPosition;
|
||||
|
||||
if (nextPosition < 0f)
|
||||
@ -352,7 +380,7 @@ namespace AlicizaX.UI
|
||||
position = 0f;
|
||||
OnValueChanged?.Invoke(position);
|
||||
StopMovement();
|
||||
StartPositionMotion(0f, 7f);
|
||||
StartPositionMotion(0f, 7f, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -361,7 +389,7 @@ namespace AlicizaX.UI
|
||||
position = maxPosition;
|
||||
OnValueChanged?.Invoke(position);
|
||||
StopMovement();
|
||||
StartPositionMotion(maxPosition, 7f);
|
||||
StartPositionMotion(maxPosition, 7f, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -378,8 +406,10 @@ namespace AlicizaX.UI
|
||||
{
|
||||
motionState = MotionState.Idle;
|
||||
velocity = 0f;
|
||||
bool shouldNotify = notifyStopped || notifyMoveStoppedOnComplete;
|
||||
notifyMoveStoppedOnComplete = false;
|
||||
|
||||
if (notifyStopped)
|
||||
if (shouldNotify)
|
||||
{
|
||||
OnMoveStoped?.Invoke();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user