2
votes

Unity: mettre à jour dynamiquement la liste déroulante lors de l'ouverture sans perdre le focus sur InputField

Je crée un Dropdown avec une barre de recherche en haut. En gros, je mets un Inputfield en haut du Dropdown .

Lorsque vous cliquez sur le Champ de saisie , la Liste déroulante s'ouvre et lorsque vous y tapez quelque chose, la Liste déroulante doit mettre à jour sa liste de manière dynamique. / p>

Voici le problème que j'ai, l'option Dropdown change dans l'inspecteur, cependant, elle ne met pas à jour la liste dans la scène.

Quand je fais Dropdown.Hide () puis Dropdown.Show () , il se met à jour mais je perds le focus sur le Inputfield . Je peux toujours simplement faire Inputfield.Select () mais ensuite tout le Inputfield est mis en surbrillance et vous devez cliquer sur la position où vous étiez pour pouvoir modifier à partir de là où vous étiez .

Des suggestions?

Modifier Voici le code ci-dessous. J'ai pris toutes les choses sans importance pour le rendre aussi mince que possible à montrer ici

public class SearchbarInput : InputField
    {
        private GameObject[] m_Ordnance;
        private Dropdown m_Dropdown;
        private SearchbarInput m_InputField;

        // Needed for basic inputfield functionality
        private List<string> m_OrdnanceNames = new List<string>(); // Used to display our data

        protected override void Start()
        {
            m_Ordnance = GetComponent<OrdnanceSelector>().m_Ordnance;

            // Get necessary components
            m_Dropdown = GetComponentInParent<Dropdown>();
            m_InputField = GetComponent<SearchbarInput>();
            m_InputField.gameObject.GetComponentInChildren<Text>().text = "Click here to select Ordnance";

            // Set InputField onValueChange listener
            m_InputField.onValueChanged.AddListener(OnInputValueChanged);

            // Add each ordnance name to our string list
            foreach (GameObject ordnance in m_Ordnance)
            {
                if (ordnance != null) m_OrdnanceNames.Add(ordnance.name);
            }
            if (m_OrdnanceNames.Count == 0) DisplayError("Ordnance were not added");
            else
            {
                ChangeDropdownOptions(m_OrdnanceNames);
                m_Dropdown.onValueChanged.AddListener((index) => OnDropdownItemClicked(index));
            }

            base.Start();
        }

        // When the InputField is selected
        public override void OnSelect(BaseEventData eventData)
        {
            base.OnSelect(eventData);
            Debug.Log("SearchbarInput selected");

            Dropdown parentDropdown = GetComponentInParent<Dropdown>();
            parentDropdown.Show();
        }

        // When the InputField is deselected
        public override void OnDeselect(BaseEventData eventData)
        {
            base.OnDeselect(eventData);
            Debug.Log("SearchbarInput deselected");
        }

        /// Displays items in list that are similar to what the user typed in the Input Field
        private void OnInputValueChanged(string typedText)
        {
            List<string> results = GetResults(typedText);
            ChangeDropdownOptions(results);
        }

        /// Get list of items that contains characters similar to input
        private List<string> GetResults(string input)
        {
            return m_OrdnanceNames.FindAll((str) => str.IndexOf(input) >= 0);
        }

        ///============================== Dropdown Methods===================================
        /// Called when the dropdown menu is clicked. Is set inside of scripts Start function
        public void OnDropdownItemClicked(int index)
        {
            // Get selected ordnance name
            string ordnanceName = m_Dropdown.options[index].text;
            m_InputField.text = ordnanceName;

            // Change AndyGenerator Prefab
            int indexOfOrdnance = m_OrdnanceNames.IndexOf(ordnanceName);
            //m_AndyScript.AndyPrefab = m_Ordnance[indexOfOrdnance]; <- Took out for StackOverflow to make as short as possible
        }

        /// Clears the dropdown options and add's options set inside of the list
        private void ChangeDropdownOptions(List<string> options)
        {
            m_Dropdown.ClearOptions();
            m_Dropdown.AddOptions(options);
        }

        ///============================== Error Method===================================
        /// Displays error inside of our InputField.
        private void DisplayError(string errorText)
        {
            Debug.Log("Searchbar.cs: " + errorText);
            // Decided to make it more obvious since this is absolutely needed and
            // it saves the headache of looking for an error
            m_InputField.text = "Error: " + errorText;
        }
    }


2 commentaires

pourriez-vous s'il vous plaît ajouter un exemple de votre code actuel pour avoir un point de départ?


@derHugo Je viens d'ajouter du code. Je vous remercie


3 Réponses :


0
votes

Je ne connais pas cette réponse, mais j'ai un problème similaire ... J'ai fait fonctionner cette barre de recherche, avec un menu déroulant affichant les valeurs dynamiques, mais ce menu déroulant ne met à jour que les caractères impairs (sur la première, la troisième ... pas la deuxième, la quatrième ...)

Ici:

//call whenever the input field changes, even OR odd, its working
public void newSearchFieldValueChanged()
{
    //read the input field, ok...   
    searchText = newSearchField.text;

    //return when empty...
    if (string.IsNullOrEmpty(searchText)) return;

    //I need to hide the dropdown   
    dropdown.Hide();

    //clear its old options
    dropdown.ClearOptions();

    //this is a dictionary to fill the dropdown options, clear it
    dicTemp.Clear();

    //add a first empty value
    dicTemp.Add("", "0");

    //so I run for another dic, that dont change its original values 
    for (int i = 0; i < dic.Keys.Count; i++)
    {
        //if it contains in its keys the word typed in the search bar...
        if (dic.Keys.ElementAt(i).ToLower().Contains(searchText.ToLower()))
        {
            //I add it to the cleared dicTemp that will fill the dropdown options   
            dicTemp.Add(dic.Keys.ElementAt(i), dic.Values.ElementAt(i));
        }
    }

    //fill the dropdown options with the new dicTemp, each time something changes
    dropdown.AddOptions(dicTemp.Keys.ToList());

    //duh
    dropdown.Show();

    //keep the focus on input field to continue type (dropdown selected by mouse)
    newSearchField.ActivateInputField();
}

Encore une fois, cela fonctionne sur la première lettre, et la troisième ... mais pas sur le deuxième et le quatrième, la liste déroulante NE S'AFFICHE PAS (en plus de la fonction est appelée à chaque fois) ...


1 commentaires

Même problème exact ici. J'ai essayé de retarder les appels avec une co-routine mais cela n'aide pas.



0
votes

@Rayaarito

Je pense

m_InputField.ActivateInputField ();

Cela devrait fonctionner pour vous, puisque vous désactivez "OnFocus - Select All" dans l'éditeur. Cela a fonctionné pour moi.


0 commentaires

1
votes

Pour vous assurer que l'interface utilisateur de la liste déroulante des options est à jour, vous devez désactiver et réactiver le composant.

Malheureusement, cela fait «scintiller» la liste déroulante. Regardez à la fin une solution "sans scintillement".

Ici, j'utilise une liste déroulante TextMeshPro.

/// <summary>
/// Call this after modifying options while the dropdown is displayed
/// to make sure the visual is up to date.
/// </summary>
public static void RefreshOptions(this TMPro.TMP_Dropdown dropdown)
{
    dropdown.enabled = false;
    dropdown.enabled = true;
    dropdown.Show();
}

Avec la méthode d'extension suivante :

Dropdown.ClearOptions();
Dropdown.AddOptions(options);

Dropdown.RefreshOptions();
InputField.Input.ActivateInputField();

 entrez la description de l'image ici

MODIFIER:

J'ai trouvé un moyen d'y parvenir ceci sans aucun scintillement. Cela implique de se débarrasser du script Dropdown et d'écrire le vôtre.

En gros, j'ai pris la même interface que pour la liste déroulante, mais j'ai placé un VerticalLayoutGroup code > dans le contenu du ScrollRect.

J'ai ensuite écrit un script personnalisé qui:

  • Afficher le ScrollRect et remplir la mise en page avec toutes les options lorsque InputField.onSelect est déclenché
  • Filtrer les options en les masquant lorsque InputField.onValueChange est déclenché (avec accélérateur)
  • Fermez le ScrollRect lorsque InputField.onEndEdit est déclenché

Et il y a des changements importants qui doivent également être apportés:

  • Le ScrollRect doit avoir un script Canvas avec un ordre de tri dédié pour être au-dessus de l'interface utilisateur
  • Le ScrollRect doit avoir un composant GraphicsRaycaster pour pouvoir sélectionner les options dans la mise en page
  • La fermeture du ScrollRect sur onEndEdit doit être effectuée avec un délai. Sinon, l'événement de clic ne sera pas évalué par les boutons de votre mise en page.

 entrez la description de l'image ici


0 commentaires