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(); _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(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); } } }