Last active
May 9, 2021 18:23
-
-
Save Z4urce/e1719b3c1641537ced54da24d911f0b0 to your computer and use it in GitHub Desktop.
Moves the Content transform so the current selected object will be inside the Viewport rect
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Source: https://gist.github.com/Z4urce/e1719b3c1641537ced54da24d911f0b0 | |
// Moves the Content transform so the current selected object will be inside the Viewport rect | |
using UnityEngine; | |
using UnityEngine.EventSystems; | |
namespace Utils | |
{ | |
public sealed class ScrollToSelectionBehaviour : MonoBehaviour | |
{ | |
public RectTransform Viewport; | |
public RectTransform Content; | |
public bool Horizontal = true; | |
public bool Vertical = true; | |
public float DistanceDeltaQuotient = 1000f; | |
public void Update() | |
{ | |
var selected = EventSystem.current.currentSelectedGameObject; | |
if (selected == null || !selected.TryGetComponent<RectTransform>(out var rectTransform)) { | |
return; | |
} | |
SnapToTarget(rectTransform); | |
} | |
private void SnapToTarget(RectTransform rectTransform) | |
{ | |
Vector2? snapPos = GetTargetRectSnapPos(rectTransform); | |
if (!snapPos.HasValue) { | |
return; | |
} | |
var anchoredPos = Content.anchoredPosition; | |
var destination = new Vector2(Horizontal ? snapPos.Value.x : anchoredPos.x, Vertical ? snapPos.Value.y : anchoredPos.y); | |
float maxDistanceDelta = Time.deltaTime * DistanceDeltaQuotient; | |
Content.anchoredPosition = Vector2.MoveTowards(anchoredPos, destination, maxDistanceDelta); | |
} | |
private Vector2? GetTargetRectSnapPos(RectTransform targetRectTransform) | |
{ | |
Canvas.ForceUpdateCanvases(); | |
var rectMinWorldPos = (Vector2) targetRectTransform.TransformPoint(targetRectTransform.rect.min); | |
var rectMaxWorldPos = (Vector2) targetRectTransform.TransformPoint(targetRectTransform.rect.max); | |
Vector2? minSnap = CalculateViewportTargetDist(rectMinWorldPos); | |
Vector2? maxSnap = CalculateViewportTargetDist(rectMaxWorldPos); | |
return maxSnap ?? minSnap; | |
} | |
private Vector2? CalculateViewportTargetDist(Vector2 globalPos) | |
{ | |
var invTransTarget = (Vector2) Viewport.InverseTransformPoint(globalPos); | |
if (Viewport.rect.Contains(invTransTarget)) { | |
return null; | |
}; | |
var invTransContent = (Vector2) Viewport.InverseTransformPoint(Content.position); | |
return invTransContent - invTransTarget; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment