Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Unity3d ScrollRect Auto-Scroll, Dropdown Use: Places this component in the Template of Dropdown (with the ScrollRect component)
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[RequireComponent(typeof(ScrollRect))]
public class ScrollRectAutoScroll : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public float scrollSpeed = 10f;
private bool mouseOver = false;
private List<Selectable> m_Selectables = new List<Selectable>();
private ScrollRect m_ScrollRect;
private Vector2 m_NextScrollPosition = Vector2.up;
void OnEnable()
{
if (m_ScrollRect)
{
m_ScrollRect.content.GetComponentsInChildren(m_Selectables);
}
}
void Awake()
{
m_ScrollRect = GetComponent<ScrollRect>();
}
void Start()
{
if (m_ScrollRect)
{
m_ScrollRect.content.GetComponentsInChildren(m_Selectables);
}
ScrollToSelected(true);
}
void Update()
{
// Scroll via input.
InputScroll();
if (!mouseOver)
{
// Lerp scrolling code.
m_ScrollRect.normalizedPosition = Vector2.Lerp(m_ScrollRect.normalizedPosition, m_NextScrollPosition, scrollSpeed * Time.deltaTime);
}
else
{
m_NextScrollPosition = m_ScrollRect.normalizedPosition;
}
}
void InputScroll()
{
if (m_Selectables.Count > 0)
{
if (Input.GetButtonDown("Horizontal") || Input.GetButtonDown("Vertical") || Input.GetButton("Horizontal") || Input.GetButton("Vertical"))
{
ScrollToSelected(false);
}
}
}
void ScrollToSelected(bool quickScroll)
{
int selectedIndex = -1;
Selectable selectedElement = EventSystem.current.currentSelectedGameObject ? EventSystem.current.currentSelectedGameObject.GetComponent<Selectable>() : null;
if (selectedElement)
{
selectedIndex = m_Selectables.IndexOf(selectedElement);
}
if (selectedIndex > -1)
{
if (quickScroll)
{
m_ScrollRect.normalizedPosition = new Vector2(0, 1 - (selectedIndex / ((float)m_Selectables.Count - 1)));
m_NextScrollPosition = m_ScrollRect.normalizedPosition;
}
else
{
m_NextScrollPosition = new Vector2(0, 1 - (selectedIndex / ((float)m_Selectables.Count - 1)));
}
}
}
public void OnPointerEnter(PointerEventData eventData)
{
mouseOver = true;
}
public void OnPointerExit(PointerEventData eventData)
{
mouseOver = false;
ScrollToSelected(false);
}
}
@mufabil45
Copy link

mufabil45 commented Apr 22, 2018

Thanks Mate You are true hero 😀

@grace7190
Copy link

grace7190 commented Nov 16, 2018

Simple & effective, thanks a bunch!

@marlon-assef
Copy link

marlon-assef commented Aug 8, 2019

Life saver script! Thanks a lot.

Remarks:
I like the behavior better without the line 87: ScrollToSelected(false);
This makes the mouse scroll works better.

@Nebuchaddy
Copy link

Nebuchaddy commented Apr 13, 2021

I know this is a bit necro af but you saved my life. Had to rewrite just a bit for the new Input System (line 52) but other than that it works like a charm. For real, thanks a bunch.

@mandarinx
Copy link
Author

mandarinx commented Apr 13, 2021

If the technique still applies, it's no necro in my opinion. Glad it's been of use to all of you. :-)

@Nebuchaddy
Copy link

Nebuchaddy commented Apr 13, 2021

If the technique still applies, it's no necro in my opinion. Glad it's been of use to all of you. :-)

Yeah, works great. Though I just spent like 30 mins trying to understand why it was working on my main menu but not on my pause menu, then I saw the Lerp function, and well, can't use Time.deltaTime if Time.timeScale is 0, so i just changed it to Time.unscaledDeltaTime, which I think is much better for UI in general, just in case.

Anyways, thanks a bunch again, i've spent hours and all I found were methods involving the dropdown component, 300 lines code, or over-complicated stuff. This is much more elegant, easy to read and understan, and really easy to implement.

Again, thanks.

@mandarinx
Copy link
Author

mandarinx commented Apr 13, 2021

Ah! Good catch. It totally agree on letting UI run on a separate timer from game time.

@Brouilles
Copy link

Brouilles commented Dec 14, 2021

@Nebuchaddy Can you share your rewrite with the new Input System?

@emredesu
Copy link

emredesu commented Jan 17, 2022

@Brouilles A bit late, but I created a fork for this in case anyone else needs it. I've tested it on PC with a keyboard, an Xbox One gamepad and on an Android phone, it worked fine on all of them.

https://gist.github.com/emredesu/af597de14a4377e1ecf96b6f7b6cc506

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