Skip to content

Instantly share code, notes, and snippets.

@Z4urce
Last active May 9, 2021 18:23
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Z4urce/e1719b3c1641537ced54da24d911f0b0 to your computer and use it in GitHub Desktop.
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
// 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