Focus/center Scroll View to the specified point/item in Unity
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
using System.Collections; | |
using UnityEngine; | |
using UnityEngine.UI; | |
public static class ScrollViewFocusFunctions | |
{ | |
public static Vector2 CalculateFocusedScrollPosition( this ScrollRect scrollView, Vector2 focusPoint ) | |
{ | |
Vector2 contentSize = scrollView.content.rect.size; | |
Vector2 viewportSize = ( (RectTransform) scrollView.content.parent ).rect.size; | |
Vector2 contentScale = scrollView.content.localScale; | |
contentSize.Scale( contentScale ); | |
focusPoint.Scale( contentScale ); | |
Vector2 scrollPosition = scrollView.normalizedPosition; | |
if( scrollView.horizontal && contentSize.x > viewportSize.x ) | |
scrollPosition.x = Mathf.Clamp01( ( focusPoint.x - viewportSize.x * 0.5f ) / ( contentSize.x - viewportSize.x ) ); | |
if( scrollView.vertical && contentSize.y > viewportSize.y ) | |
scrollPosition.y = Mathf.Clamp01( ( focusPoint.y - viewportSize.y * 0.5f ) / ( contentSize.y - viewportSize.y ) ); | |
return scrollPosition; | |
} | |
public static Vector2 CalculateFocusedScrollPosition( this ScrollRect scrollView, RectTransform item ) | |
{ | |
Vector2 itemCenterPoint = scrollView.content.InverseTransformPoint( item.transform.TransformPoint( item.rect.center ) ); | |
Vector2 contentSizeOffset = scrollView.content.rect.size; | |
contentSizeOffset.Scale( scrollView.content.pivot ); | |
return scrollView.CalculateFocusedScrollPosition( itemCenterPoint + contentSizeOffset ); | |
} | |
public static void FocusAtPoint( this ScrollRect scrollView, Vector2 focusPoint ) | |
{ | |
scrollView.normalizedPosition = scrollView.CalculateFocusedScrollPosition( focusPoint ); | |
} | |
public static void FocusOnItem( this ScrollRect scrollView, RectTransform item ) | |
{ | |
scrollView.normalizedPosition = scrollView.CalculateFocusedScrollPosition( item ); | |
} | |
private static IEnumerator LerpToScrollPositionCoroutine( this ScrollRect scrollView, Vector2 targetNormalizedPos, float speed ) | |
{ | |
Vector2 initialNormalizedPos = scrollView.normalizedPosition; | |
float t = 0f; | |
while( t < 1f ) | |
{ | |
scrollView.normalizedPosition = Vector2.LerpUnclamped( initialNormalizedPos, targetNormalizedPos, 1f - ( 1f - t ) * ( 1f - t ) ); | |
yield return null; | |
t += speed * Time.unscaledDeltaTime; | |
} | |
scrollView.normalizedPosition = targetNormalizedPos; | |
} | |
public static IEnumerator FocusAtPointCoroutine( this ScrollRect scrollView, Vector2 focusPoint, float speed ) | |
{ | |
yield return scrollView.LerpToScrollPositionCoroutine( scrollView.CalculateFocusedScrollPosition( focusPoint ), speed ); | |
} | |
public static IEnumerator FocusOnItemCoroutine( this ScrollRect scrollView, RectTransform item, float speed ) | |
{ | |
yield return scrollView.LerpToScrollPositionCoroutine( scrollView.CalculateFocusedScrollPosition( item ), speed ); | |
} | |
} |
Huge help. Thanks!
Wow
Thanks a lot for sharing this. Great!!!
Thank you! I had my own system, but yours is more accurate
Thank you, You are awesome man
Really nice thank you !
for those who want to chain up scroll coroutine and cancel the previous one to avoid glitches.
here are some new coroutine functions
public static bool cancelOutPreviousCoroutine = false;
public static int runningLerpCoroutine = 0;
private static IEnumerator LerpToScrollPositionCoroutine( this ScrollRect scrollView, Vector2 targetNormalizedPos, float speed )
{
Vector2 initialNormalizedPos = scrollView.normalizedPosition;
float t = 0f;
while( t < 1f )
{
scrollView.normalizedPosition = Vector2.LerpUnclamped( initialNormalizedPos, targetNormalizedPos, 1f - ( 1f - t ) * ( 1f - t ) );
yield return null;
t += speed * Time.unscaledDeltaTime;
if (cancelOutPreviousCoroutine) {
t = 1;
cancelOutPreviousCoroutine = false;
}
if (t < 1f) {
scrollView.normalizedPosition = targetNormalizedPos;
}
}
runningLerpCoroutine--;
}
public static IEnumerator FocusAtPointCoroutine( this ScrollRect scrollView, Vector2 focusPoint, float speed )
{
if (runningLerpCoroutine > 0) cancelOutPreviousCoroutine = true;
runningLerpCoroutine++;
yield return scrollView.LerpToScrollPositionCoroutine( scrollView.CalculateFocusedScrollPosition( focusPoint ), speed );
}
public static IEnumerator FocusOnItemCoroutine( this ScrollRect scrollView, RectTransform item, float speed )
{
if (runningLerpCoroutine > 0) cancelOutPreviousCoroutine = true;
runningLerpCoroutine++;
yield return scrollView.LerpToScrollPositionCoroutine( scrollView.CalculateFocusedScrollPosition( item ), speed );
}
I can't express how I thank you. This works just perfect! Thank you very much.
Thanks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How To
After adding the above C# script to your project, simply call
scrollView.FocusOnItem( targetItem )
. To focus on that item smoothly, callStartCoroutine( scrollView.FocusOnItemCoroutine( targetItem, focusSpeed ) )
. Don't call FocusOnItemCoroutine every frame, wait for it to finish first.