107 lines
3.2 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|