Hi,
I have a question regarding the Dropdown component (Redirecting to latest version of com.unity.ugui)
From the docs : “Once clicked, it opens up the list of options so a new option can be chosen.”
I have a lot of options (let’s say 100) and I would like to open the list of options around the current item in the dropdown avoiding the tedious manual scrolling for the user.
For example: the current item is the 50th, if I click the Dropdown it should show items around that (48-52)
Thank you
Ok, I solved my own problem with a ugly piece of code:
public void OnPointerClickDelegate(string data)
{
GameObject ddl = GameObject.Find("Dropdown List");
GameObject vp = ddl.GetComponentsInChildren<RectTransform>()[1].gameObject;
GameObject content = vp.GetComponentsInChildren<RectTransform>()[1].gameObject;
RectTransform rt = content.GetComponent<RectTransform>();
int index = Dropdown.value;
// 75 is the height of an item in my dropdown
rt.position = rt.position + Vector3.up * index * 75;
}
As you can see I reach the transform of the options content and set its position to a value proportional to the current index in the dropdown.
Please note:
The code uses Find, which I don’t like (because it works with fragile strings)
The code relies on GetComponentsInChildren items position (which is not guaranteed)
You can optimize the hierarchy accessors, I wanted to explicit my purposes here
You need to trigger this function adding an Event Trigger on the Dropdown component from the inspector.
4 Likes
THANKS ALOT, WORKS PERFECTLY
Another solution:
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);
}
}
Use: Places this component in the Template of Dropdown (with the ScrollRect component)
Link to original: Unity3d ScrollRect Auto-Scroll, Dropdown Use: Places this component in the Template of Dropdown (with the ScrollRect component) · GitHub
I created this simple script to solve the problem:
//The TMP Dropdown object in the unity hierarchy has a "Template" object as a child, in that object is a "Viewport" and a "Scrollbar".
//Place this script on that "Scrollbar" object in the "Template".
//This will get called once on Start due to the script on the template, that is why there is a null check below,
// otherwise this gets created every time the Dropdown menu is activated, it reads what value the dropdown is at and creates a ratio to
// the total number of objects. Then it sets the scrollbar value to that ratio less than one. This puts the selected option in the viewport
// everytime the Dropdown is activated.
//
// ---JCC913z---
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class DropdownHandler : MonoBehaviour
{
Scrollbar _scrollbar;
TMP_Dropdown _dropdown;
private void Start()
{
_dropdown = GetComponentInParent<TMP_Dropdown>();
_scrollbar = GetComponent<Scrollbar>();
if (_scrollbar != null) { GoToSelected(); }
}
private void GoToSelected()
{
float selectedOption = _dropdown.value;
float ratio = selectedOption / _dropdown.options.Count;
_scrollbar.value = 1f - ratio;
}
}
Hope this helps someone!
Great solution, thank you so much!