This commit is contained in:
陈思海 2025-12-26 15:39:31 +08:00
parent 26c205ddc0
commit ca46f80d67
7 changed files with 246 additions and 0 deletions

View File

@ -378,6 +378,87 @@ namespace AlicizaX.UI
UpdateCurrentIndex(index); 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 #endregion
#region Private Methods - Scroll Callbacks #region Private Methods - Scroll Callbacks

View File

@ -0,0 +1,23 @@
namespace AlicizaX.UI
{
/// <summary>
/// Defines how an item should be aligned when scrolling to it
/// </summary>
public enum ScrollAlignment
{
/// <summary>
/// Align item to the top/left of the viewport
/// </summary>
Start,
/// <summary>
/// Align item to the center of the viewport
/// </summary>
Center,
/// <summary>
/// Align item to the bottom/right of the viewport
/// </summary>
End
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d17e4def4547e70499c0f63802da2772
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,94 @@
using System;
using UnityEngine;
namespace AlicizaX.UI
{
/// <summary>
/// Extension methods for UGList to provide enhanced scrolling functionality
/// </summary>
public static class UGListExtensions
{
/// <summary>
/// Enable debug logging for ScrollTo operations
/// </summary>
public static bool DebugScrollTo { get; set; } = false;
/// <summary>
/// Scrolls to a specific item with alignment and animation options
/// </summary>
/// <param name="ugList">The UGList instance</param>
/// <param name="index">The index of the item to scroll to</param>
/// <param name="alignment">How to align the item in the viewport (Start, Center, or End)</param>
/// <param name="offset">Additional offset in pixels to apply after alignment</param>
/// <param name="smooth">Whether to animate the scroll</param>
/// <param name="duration">Animation duration in seconds (only used when smooth is true)</param>
public static void ScrollTo<TData, TAdapter>(
this UGListBase<TData, TAdapter> ugList,
int index,
ScrollAlignment alignment = ScrollAlignment.Start,
float offset = 0f,
bool smooth = false,
float duration = 0.3f)
where TAdapter : Adapter<TData>
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);
}
/// <summary>
/// Scrolls to a specific item and aligns it at the start (top/left) of the viewport
/// </summary>
public static void ScrollToStart<TData, TAdapter>(
this UGListBase<TData, TAdapter> ugList,
int index,
float offset = 0f,
bool smooth = false,
float duration = 0.3f)
where TAdapter : Adapter<TData>
where TData : ISimpleViewData
{
ugList.ScrollTo(index, ScrollAlignment.Start, offset, smooth, duration);
}
/// <summary>
/// Scrolls to a specific item and aligns it at the center of the viewport
/// </summary>
public static void ScrollToCenter<TData, TAdapter>(
this UGListBase<TData, TAdapter> ugList,
int index,
float offset = 0f,
bool smooth = false,
float duration = 0.3f)
where TAdapter : Adapter<TData>
where TData : ISimpleViewData
{
ugList.ScrollTo(index, ScrollAlignment.Center, offset, smooth, duration);
}
/// <summary>
/// Scrolls to a specific item and aligns it at the end (bottom/right) of the viewport
/// </summary>
public static void ScrollToEnd<TData, TAdapter>(
this UGListBase<TData, TAdapter> ugList,
int index,
float offset = 0f,
bool smooth = false,
float duration = 0.3f)
where TAdapter : Adapter<TData>
where TData : ISimpleViewData
{
ugList.ScrollTo(index, ScrollAlignment.End, offset, smooth, duration);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a8f3c4e7d9b24f1a8c5e2d6f3a7b9c1e
timeCreated: 1735197600

View File

@ -0,0 +1,31 @@
Simple Test
public class TestData : ISimpleViewData
{
public string Name;
}
public class TestRecyclerView : MonoBehaviour
{
public RecyclerView itemListView;
public UGList<TestData> list;
void Start()
{
list = UGListCreateHelper.Create<TestData>(itemListView, OnBtnItemClick);
List<TestData> 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);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c0bd5104eb4344798791ff94b29eb63b
timeCreated: 1766730473