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