ProjectDDD/Assets/_DDD/_Scripts/GameUi/ScrollViewUi/AutoScrollToSelected.cs
2025-08-06 13:22:30 +09:00

107 lines
3.2 KiB
C#

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace DDD
{
public class AutoScrollToSelected : MonoBehaviour
{
private ScrollRect _scrollRect;
private RectTransform _viewport;
private RectTransform _content;
private GameObject _lastSelected;
private bool _wasScrolling;
private void Awake()
{
_scrollRect = GetComponent<ScrollRect>();
_viewport = _scrollRect.viewport;
_content = _scrollRect.content;
}
private void Update()
{
if (_scrollRect.velocity.sqrMagnitude > 0.01f)
{
_wasScrolling = true;
return;
}
if (_wasScrolling)
{
_wasScrolling = false;
return;
}
var selected = EventSystem.current.currentSelectedGameObject;
if (selected == null || selected == _lastSelected) return;
_lastSelected = selected;
if (!selected.TryGetComponent<IAutoScrollItem>(out var autoScrollItem)) return;
var target = autoScrollItem.RectTransform;
if (!target.IsChildOf(_content)) return;
if (!IsFullyVisible(target))
{
ScrollToMakeFullyVisible(target);
}
}
private bool IsFullyVisible(RectTransform target)
{
var worldCorners = new Vector3[4];
target.GetWorldCorners(worldCorners);
for (int i = 0; i < 4; i++)
{
Vector3 local = _viewport.InverseTransformPoint(worldCorners[i]);
if (!_viewport.rect.Contains(local)) return false;
}
return true;
}
private void ScrollToMakeFullyVisible(RectTransform target)
{
Canvas.ForceUpdateCanvases();
float scrollRange = _content.rect.height - _viewport.rect.height;
if (scrollRange <= 0f) return;
Vector3[] itemCorners = new Vector3[4];
target.GetWorldCorners(itemCorners);
Vector3[] viewportCorners = new Vector3[4];
_viewport.GetWorldCorners(viewportCorners);
float itemTop = itemCorners[1].y;
float itemBottom = itemCorners[0].y;
float viewTop = viewportCorners[1].y;
float viewBottom = viewportCorners[0].y;
float offset = 0f;
float normalizedDelta = 0f;
if (itemTop > viewTop)
{
offset = itemTop - viewTop;
normalizedDelta = offset / scrollRange;
_scrollRect.verticalNormalizedPosition += normalizedDelta;
}
else if (itemBottom < viewBottom)
{
offset = viewBottom - itemBottom;
normalizedDelta = offset / scrollRange;
_scrollRect.verticalNormalizedPosition -= normalizedDelta;
}
else
{
return;
}
_scrollRect.verticalNormalizedPosition = Mathf.Clamp01(_scrollRect.verticalNormalizedPosition);
}
}
}