Skip to content

Instantly share code, notes, and snippets.

@phosphoer
Last active October 3, 2024 00:54
Show Gist options
  • Save phosphoer/5c6bdb93a6e518200f6ce680489ad4b3 to your computer and use it in GitHub Desktop.
Save phosphoer/5c6bdb93a6e518200f6ce680489ad4b3 to your computer and use it in GitHub Desktop.
Custom Unity ScrollRect
using UnityEngine;
public class ScrollRectTransform : MonoBehaviour
{
public Vector2 ScrollPosition
{
get => _content.anchoredPosition;
set => SetScrollPosition(value);
}
public bool EnableHorizontal = true;
public bool EnableVertical = true;
[SerializeField]
private RectTransform _content = null;
// Calculate the absolute scroll position that will bring targetTransform
// directly to the center of the scroll view
public Vector2 GetCenterScrollPos(RectTransform targetTransform)
{
RectTransform viewport = transform as RectTransform;
Bounds elementBounds = targetTransform.TransformBoundsTo(viewport);
float offsetX = EnableHorizontal ? viewport.rect.center.x - elementBounds.center.x : 0;
float offsetY = EnableVertical ? viewport.rect.center.y - elementBounds.center.y : 0;
return new Vector2(offsetX, offsetY) + _content.anchoredPosition;
}
// Calculate the absolute scroll position such that the target transform
// is brought into view with optional padding with the minimal movement necessary
public Vector2 GetClampedScrollPos(RectTransform targetTransform, float padding = 0)
{
RectTransform viewport = transform as RectTransform;
Rect viewportRect = viewport.rect;
Bounds elementBounds = targetTransform.TransformBoundsTo(viewport);
elementBounds.Expand(padding);
float offsetX = Mathf.Max(0, viewportRect.min.x - elementBounds.min.x)
- Mathf.Max(0, elementBounds.max.x - viewportRect.max.x);
float offsetY = Mathf.Max(0, viewportRect.min.y - elementBounds.min.y)
- Mathf.Max(0, elementBounds.max.y - viewportRect.max.y);
return new Vector2(EnableHorizontal ? offsetX : 0, EnableVertical ? offsetY : 0) + _content.anchoredPosition;
}
private void SetScrollPosition(Vector2 scrollPos)
{
_content.anchoredPosition = scrollPos;
}
}
using UnityEngine;
using UnityEngine.UI;
public static class UIExtensions
{
/// <summary>
/// Transform the bounds of the current rect transform to the space of another transform.
/// </summary>
/// <param name="source">The rect to transform</param>
/// <param name="target">The target space to transform to</param>
/// <returns>The transformed bounds</returns>
private static Vector3[] _corners = new Vector3[4];
public static Bounds TransformBoundsTo(this RectTransform source, Transform target)
{
// Based on code in ScrollRect's internal GetBounds and InternalGetBounds methods
var bounds = new Bounds();
if (source != null)
{
source.GetWorldCorners(_corners);
var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
var matrix = target.worldToLocalMatrix;
for (int j = 0; j < 4; j++)
{
Vector3 v = matrix.MultiplyPoint3x4(_corners[j]);
vMin = Vector3.Min(v, vMin);
vMax = Vector3.Max(v, vMax);
}
bounds = new Bounds(vMin, Vector3.zero);
bounds.Encapsulate(vMax);
}
return bounds;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment