Skip to content

Instantly share code, notes, and snippets.

@yasirkula
Created October 23, 2021 10:09
Show Gist options
  • Star 50 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save yasirkula/75ca350fb83ddcc1558d33a8ecf1483f to your computer and use it in GitHub Desktop.
Save yasirkula/75ca350fb83ddcc1558d33a8ecf1483f to your computer and use it in GitHub Desktop.
Focus/center Scroll View to the specified point/item in Unity
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 );
}
}
@yasirkula
Copy link
Author

How To

After adding the above C# script to your project, simply call scrollView.FocusOnItem( targetItem ). To focus on that item smoothly, call StartCoroutine( scrollView.FocusOnItemCoroutine( targetItem, focusSpeed ) ). Don't call FocusOnItemCoroutine every frame, wait for it to finish first.

@burst2flame
Copy link

Huge help. Thanks!

@GuyGinat
Copy link

Wow

@mh-studios
Copy link

Thanks a lot for sharing this. Great!!!

@DeniMN
Copy link

DeniMN commented Apr 21, 2023

Thank you! I had my own system, but yours is more accurate

@MohamadJavadGholizade
Copy link

Thank you, You are awesome man

@Enlumis
Copy link

Enlumis commented Jun 28, 2023

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

@ViacheslavWeaver
Copy link

I can't express how I thank you. This works just perfect! Thank you very much.

@alamin-khalid
Copy link

Thanks

@hadisajjadi
Copy link

Great. thank you

@gimpycpu
Copy link

gimpycpu commented Feb 2, 2024

Hello sir, I'd like to use your code but there is no license could you please add one when you have time :)

Thank you

@yasirkula
Copy link
Author

@gimpycpu Hi! Feel free to use it under MIT License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment