From ca46f80d674efe7410e3988512eeb97e3d40b9ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com>
Date: Fri, 26 Dec 2025 15:39:31 +0800
Subject: [PATCH] fix
---
Runtime/RecyclerView/RecyclerView.cs | 81 ++++++++++++++++
Runtime/RecyclerView/ScrollAlignment.cs | 23 +++++
Runtime/RecyclerView/ScrollAlignment.cs.meta | 11 +++
Runtime/RecyclerView/UGListExtensions.cs | 94 +++++++++++++++++++
Runtime/RecyclerView/UGListExtensions.cs.meta | 3 +
Runtime/RecyclerView/readme.md | 31 ++++++
Runtime/RecyclerView/readme.md.meta | 3 +
7 files changed, 246 insertions(+)
create mode 100644 Runtime/RecyclerView/ScrollAlignment.cs
create mode 100644 Runtime/RecyclerView/ScrollAlignment.cs.meta
create mode 100644 Runtime/RecyclerView/UGListExtensions.cs
create mode 100644 Runtime/RecyclerView/UGListExtensions.cs.meta
create mode 100644 Runtime/RecyclerView/readme.md
create mode 100644 Runtime/RecyclerView/readme.md.meta
diff --git a/Runtime/RecyclerView/RecyclerView.cs b/Runtime/RecyclerView/RecyclerView.cs
index 1a8eeaf..940d4d1 100644
--- a/Runtime/RecyclerView/RecyclerView.cs
+++ b/Runtime/RecyclerView/RecyclerView.cs
@@ -378,6 +378,87 @@ namespace AlicizaX.UI
UpdateCurrentIndex(index);
}
+ public void ScrollToWithAlignment(int index, ScrollAlignment alignment, float offset = 0f, bool smooth = false, float duration = 0.3f)
+ {
+ if (!scroll || scroller == null) return;
+
+ float targetPosition = CalculateScrollPositionWithAlignment(index, alignment, offset);
+
+ if (UGListExtensions.DebugScrollTo)
+ {
+ Debug.Log($"[RecyclerView] ScrollToWithAlignment: index={index}, alignment={alignment}, offset={offset}, targetPosition={targetPosition}, maxPosition={scroller.MaxPosition}");
+ }
+
+ if (duration > 0 && smooth)
+ {
+ scroller.ScrollTo(targetPosition, true);
+ }
+ else
+ {
+ scroller.ScrollTo(targetPosition, smooth);
+ }
+
+ if (!smooth)
+ {
+ Refresh();
+ }
+
+ UpdateCurrentIndex(index);
+ }
+
+ private float CalculateScrollPositionWithAlignment(int index, ScrollAlignment alignment, float offset)
+ {
+ if (RecyclerViewAdapter == null || index < 0 || index >= RecyclerViewAdapter.GetItemCount())
+ {
+ return scroller.Position;
+ }
+
+ float itemSize = GetItemSize(index);
+ float viewportLength = direction == Direction.Vertical ? layoutManager.ViewportSize.y : layoutManager.ViewportSize.x;
+ float contentLength = direction == Direction.Vertical ? layoutManager.ContentSize.y : layoutManager.ContentSize.x;
+
+ // Calculate the raw position of the item (without any clamping)
+ float itemPosition = CalculateRawItemPosition(index);
+
+ float targetPosition = alignment switch
+ {
+ ScrollAlignment.Start => itemPosition,
+ ScrollAlignment.Center => itemPosition - (viewportLength - itemSize) / 2f,
+ ScrollAlignment.End => itemPosition - viewportLength + itemSize,
+ _ => itemPosition
+ };
+
+ // Apply custom offset
+ targetPosition += offset;
+
+ if (UGListExtensions.DebugScrollTo)
+ {
+ Debug.Log($"[RecyclerView] CalculateScrollPosition: index={index}, itemPosition={itemPosition}, itemSize={itemSize}, viewportLength={viewportLength}, contentLength={contentLength}, targetPosition={targetPosition}, maxPosition={scroller.MaxPosition}");
+ }
+
+ // Clamp to valid scroll range
+ return Mathf.Clamp(targetPosition, 0, scroller.MaxPosition);
+ }
+
+ private float CalculateRawItemPosition(int index)
+ {
+ // Get spacing based on direction
+ Vector2 spacing = layoutManager.Spacing;
+ Vector2 padding = layoutManager.Padding;
+ float itemSize = GetItemSize(index);
+ float spacingValue = direction == Direction.Vertical ? spacing.y : spacing.x;
+ float paddingValue = direction == Direction.Vertical ? padding.y : padding.x;
+
+ // Calculate raw position without clamping
+ return index * (itemSize + spacingValue) + paddingValue;
+ }
+
+ private float GetItemSize(int index)
+ {
+ Vector2 itemSize = ViewProvider.CalculateViewSize(index);
+ return direction == Direction.Vertical ? itemSize.y : itemSize.x;
+ }
+
#endregion
#region Private Methods - Scroll Callbacks
diff --git a/Runtime/RecyclerView/ScrollAlignment.cs b/Runtime/RecyclerView/ScrollAlignment.cs
new file mode 100644
index 0000000..0dc3bd3
--- /dev/null
+++ b/Runtime/RecyclerView/ScrollAlignment.cs
@@ -0,0 +1,23 @@
+namespace AlicizaX.UI
+{
+ ///
+ /// Defines how an item should be aligned when scrolling to it
+ ///
+ public enum ScrollAlignment
+ {
+ ///
+ /// Align item to the top/left of the viewport
+ ///
+ Start,
+
+ ///
+ /// Align item to the center of the viewport
+ ///
+ Center,
+
+ ///
+ /// Align item to the bottom/right of the viewport
+ ///
+ End
+ }
+}
diff --git a/Runtime/RecyclerView/ScrollAlignment.cs.meta b/Runtime/RecyclerView/ScrollAlignment.cs.meta
new file mode 100644
index 0000000..59e19e1
--- /dev/null
+++ b/Runtime/RecyclerView/ScrollAlignment.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d17e4def4547e70499c0f63802da2772
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/RecyclerView/UGListExtensions.cs b/Runtime/RecyclerView/UGListExtensions.cs
new file mode 100644
index 0000000..2940c24
--- /dev/null
+++ b/Runtime/RecyclerView/UGListExtensions.cs
@@ -0,0 +1,94 @@
+using System;
+using UnityEngine;
+
+namespace AlicizaX.UI
+{
+ ///
+ /// Extension methods for UGList to provide enhanced scrolling functionality
+ ///
+ public static class UGListExtensions
+ {
+ ///
+ /// Enable debug logging for ScrollTo operations
+ ///
+ public static bool DebugScrollTo { get; set; } = false;
+
+ ///
+ /// Scrolls to a specific item with alignment and animation options
+ ///
+ /// The UGList instance
+ /// The index of the item to scroll to
+ /// How to align the item in the viewport (Start, Center, or End)
+ /// Additional offset in pixels to apply after alignment
+ /// Whether to animate the scroll
+ /// Animation duration in seconds (only used when smooth is true)
+ public static void ScrollTo(
+ this UGListBase ugList,
+ int index,
+ ScrollAlignment alignment = ScrollAlignment.Start,
+ float offset = 0f,
+ bool smooth = false,
+ float duration = 0.3f)
+ where TAdapter : Adapter
+ where TData : ISimpleViewData
+ {
+ if (ugList?.RecyclerView == null)
+ {
+ Debug.LogWarning("UGList or RecyclerView is null");
+ return;
+ }
+
+ if (DebugScrollTo)
+ {
+ Debug.Log($"[UGListExtensions] ScrollTo: index={index}, alignment={alignment}, offset={offset}, smooth={smooth}, duration={duration}");
+ }
+
+ ugList.RecyclerView.ScrollToWithAlignment(index, alignment, offset, smooth, duration);
+ }
+
+ ///
+ /// Scrolls to a specific item and aligns it at the start (top/left) of the viewport
+ ///
+ public static void ScrollToStart(
+ this UGListBase ugList,
+ int index,
+ float offset = 0f,
+ bool smooth = false,
+ float duration = 0.3f)
+ where TAdapter : Adapter
+ where TData : ISimpleViewData
+ {
+ ugList.ScrollTo(index, ScrollAlignment.Start, offset, smooth, duration);
+ }
+
+ ///
+ /// Scrolls to a specific item and aligns it at the center of the viewport
+ ///
+ public static void ScrollToCenter(
+ this UGListBase ugList,
+ int index,
+ float offset = 0f,
+ bool smooth = false,
+ float duration = 0.3f)
+ where TAdapter : Adapter
+ where TData : ISimpleViewData
+ {
+ ugList.ScrollTo(index, ScrollAlignment.Center, offset, smooth, duration);
+ }
+
+ ///
+ /// Scrolls to a specific item and aligns it at the end (bottom/right) of the viewport
+ ///
+ public static void ScrollToEnd(
+ this UGListBase ugList,
+ int index,
+ float offset = 0f,
+ bool smooth = false,
+ float duration = 0.3f)
+ where TAdapter : Adapter
+ where TData : ISimpleViewData
+ {
+ ugList.ScrollTo(index, ScrollAlignment.End, offset, smooth, duration);
+ }
+ }
+}
diff --git a/Runtime/RecyclerView/UGListExtensions.cs.meta b/Runtime/RecyclerView/UGListExtensions.cs.meta
new file mode 100644
index 0000000..1d4eb62
--- /dev/null
+++ b/Runtime/RecyclerView/UGListExtensions.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a8f3c4e7d9b24f1a8c5e2d6f3a7b9c1e
+timeCreated: 1735197600
diff --git a/Runtime/RecyclerView/readme.md b/Runtime/RecyclerView/readme.md
new file mode 100644
index 0000000..2601c19
--- /dev/null
+++ b/Runtime/RecyclerView/readme.md
@@ -0,0 +1,31 @@
+Simple Test
+
+public class TestData : ISimpleViewData
+{
+public string Name;
+}
+
+public class TestRecyclerView : MonoBehaviour
+{
+public RecyclerView itemListView;
+public UGList list;
+
+ void Start()
+ {
+ list = UGListCreateHelper.Create(itemListView, OnBtnItemClick);
+
+ List datas = new();
+ for (int i = 0; i < 150; i++)
+ {
+ datas.Add(new TestData { Name = $"Item {i}" });
+ }
+
+ list.Data = datas;
+ }
+
+ private void OnBtnItemClick(TestData obj)
+ {
+ Debug.Log(obj.Name);
+ }
+
+}
diff --git a/Runtime/RecyclerView/readme.md.meta b/Runtime/RecyclerView/readme.md.meta
new file mode 100644
index 0000000..17462ea
--- /dev/null
+++ b/Runtime/RecyclerView/readme.md.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c0bd5104eb4344798791ff94b29eb63b
+timeCreated: 1766730473
\ No newline at end of file