web-dev-qa-db-fra.com

Xamarin.Forms, plate-forme croisée à remplissage automatique

Je suis un débutant sur la plate-forme Xamarin.Forms. J'espère que vous pourrez m'aider à progresser. Je veux avoir un contrôle comme autocomplete dans xamarin.forms comme ci-dessous 

 Autocomplete

Pouvez-vous s'il vous plaît indiquer comment cela peut être réalisé dans Xamarin.Forms? Je veux y parvenir avec le contrôle d'entrée

TIA

8
Manoj Sethi

Vous n'avez pas inclus ce que vous voulez exactement, juste une sorte de saisie semi-automatique.

Je vais faire un point sur la manière manuelle de le faire pour une liste d'éléments:

  1. Utilisez une zone de texte pour permettre à l'utilisateur de saisir du texte.
  2. Utilisez une liste pour regrouper tous vos objets avec leur propriété interrogeable, telle que le nom de l'objet.
  3. Lorsque l'utilisateur tape quelque chose dans la zone de texte, l'application doit rechercher dans la liste la chaîne entrée dans la zone de texte.
  4. Les suggestions doivent être affichées, en fonction de la valeur de chaîne saisie, dans un ListView sous la zone de texte.
  5. L'utilisateur clique sur l'élément ListView, ce qui est une suggestion, puis le complète automatiquement en prenant le nom de l'objet de l'élément sur lequel il a cliqué dans la zone de texte.

Une façon générale de procéder à la saisie semi-automatique sans la procédure approximative longue ci-dessus consiste à utiliser Android AutoCompleteTextView.

Vous pouvez toujours utiliser la logique de base pour le faire dans Xamarin Forms.

Regardez ici pour AutoCompleteTextView pour Android . Regardez ici , ici et ici pour obtenir de l'aide sur la saisie semi-automatique dans Xamarin Forms.

8
Imdad

J'ai implémenté une AutocompleteView dans mon projet. Vous pouvez le référer.

public class AutoCompleteView : ContentView
{
    public static readonly BindableProperty SuggestionsProperty = BindableProperty.Create(nameof(Suggestions), typeof(IEnumerable), typeof(AutoCompleteView), null, BindingMode.OneWay, null, OnSuggestionsChanged);
    public static readonly BindableProperty SearchTextProperty = BindableProperty.Create(nameof(SearchText), typeof(string), typeof(AutoCompleteView), null, BindingMode.TwoWay, null, OnSearchTextChanged);
    public static readonly BindableProperty PlaceholderProperty = BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(AutoCompleteView), null, BindingMode.OneWay, null, OnPlaceholderChanged);
    public static readonly BindableProperty MaximumVisibleSuggestionItemsProperty = BindableProperty.Create(nameof(MaximumVisibleSuggestionItems), typeof(int), typeof(AutoCompleteView), 4);
    public static readonly BindableProperty SuggestionItemTemplateProperty = BindableProperty.Create(nameof(SuggestionItemTemplate), typeof(DataTemplate), typeof(AutoCompleteView), null, BindingMode.OneWay, null, OnSuggestionItemTemplateChanged);
    public static readonly BindableProperty DisplayPropertyNameProperty = BindableProperty.Create(nameof(DisplayPropertyName), typeof(string), typeof(AutoCompleteView));

    public IEnumerable Suggestions
    {
        get { return (IEnumerable)GetValue(SuggestionsProperty); }
        set { SetValue(SuggestionsProperty, value); }
    }

    public string SearchText
    {
        get { return (string)GetValue(SearchTextProperty); }
        set { SetValue(SearchTextProperty, value); }
    }

    public string Placeholder
    {
        get { return (string)GetValue(PlaceholderProperty); }
        set { SetValue(PlaceholderProperty, value); }
    }

    public int MaximumVisibleSuggestionItems
    {
        get { return (int)GetValue(MaximumVisibleSuggestionItemsProperty); }
        set { SetValue(MaximumVisibleSuggestionItemsProperty, value); }
    }

    public DataTemplate SuggestionItemTemplate
    {
        get { return (DataTemplate)GetValue(SuggestionItemTemplateProperty); }
        set { SetValue(SuggestionItemTemplateProperty, value); }
    }

    public string DisplayPropertyName
    {
        get { return (string)GetValue(DisplayPropertyNameProperty); }
        set { SetValue(DisplayPropertyNameProperty, value); }
    }

    public ItemsStack SuggestionsListView { get; private set; }
    public Entry SearchEntry { get; private set; }
    public IEnumerable OriginSuggestions { get; private set; }
    public NestedScrollView SuggestionWrapper { get; private set; }
    public Grid Container { get; private set; }

    public bool IsSelected { get; private set; }
    public int TotalNumberOfTypings { get; private set; }

    private static void OnSuggestionsChanged(object bindable, object oldValue, object newValue)
    {
        var autoCompleteView = bindable as AutoCompleteView;

        var suggestions = (IEnumerable)newValue;
        autoCompleteView.OriginSuggestions = suggestions;

        suggestions = autoCompleteView.FilterSuggestions(suggestions, autoCompleteView.SearchText);
        autoCompleteView.SuggestionsListView.ItemsSource = suggestions;
    }

    private static void OnSearchTextChanged(object bindable, object oldValue, object newValue)
    {
        var autoCompleteView = bindable as AutoCompleteView;

        var suggestions = autoCompleteView.OriginSuggestions;
        if (newValue != null)
        {
            suggestions = autoCompleteView.FilterSuggestions(suggestions, autoCompleteView.SearchText);
            // assign when initializing with data
            if (autoCompleteView.SearchEntry.Text != autoCompleteView.SearchText)
            {
                autoCompleteView.SearchEntry.Text = autoCompleteView.SearchText;
            }
        }
        autoCompleteView.SuggestionsListView.ItemsSource = suggestions;

        if (Device.OS == TargetPlatform.Android)
        {
            // update the layout -> only do this when user is typing instead of selection an item from suggestions list 
            // -> prevent duplicated update layout
            if (!autoCompleteView.IsSelected)
            {
                autoCompleteView.UpdateLayout();
            }
            else
            {
                autoCompleteView.IsSelected = false;
            }
        }
    }

    private static void OnSuggestionItemTemplateChanged(object bindable, object oldValue, object newValue)
    {
        var autoCompleteView = bindable as AutoCompleteView;

        if (autoCompleteView.SuggestionsListView != null)
        {
            autoCompleteView.SuggestionsListView.ItemTemplate = autoCompleteView.SuggestionItemTemplate;
        }
    }

    public IEnumerable FilterSuggestions(IEnumerable suggestions, string keyword)
    {
        if (string.IsNullOrEmpty(keyword) || suggestions == null) return suggestions;

        var searchWords = keyword.ConvertToNonMark().ToLower().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
        var result = suggestions.Cast<object>();
        foreach (var item in searchWords)
        {
            if (!string.IsNullOrEmpty(DisplayPropertyName))
            {
                result = result.Where(x => x.GetType().GetRuntimeProperty(DisplayPropertyName).GetValue(x).ToString().ConvertToNonMark().ToLower().Contains(item)).ToList();
            }
            else
            {
                result = result.Where(x => x.ToString().ConvertToNonMark().ToLower().Contains(item)).ToList();
            }
        }

        return result;
    }

    private static void OnPlaceholderChanged(object bindable, object oldValue, object newValue)
    {
        var autoCompleteView = bindable as AutoCompleteView;
        autoCompleteView.SearchEntry.Placeholder = newValue?.ToString();
    }

    public void UpdateLayout()
    {
        var expectedHeight = this.getExpectedHeight();
        Container.HeightRequest = expectedHeight;
        Container.ForceLayout();
    }

    private void SearchEntry_TextChanged(object sender, TextChangedEventArgs e)
    {
        TotalNumberOfTypings++;
        Device.StartTimer(TimeSpan.FromMilliseconds(1000), () => {
            TotalNumberOfTypings--;
            if (TotalNumberOfTypings == 0)
            {
                SearchText = e.NewTextValue;
            }
            return false;
        });
    }

    private void SearchEntry_Focused(object sender, FocusEventArgs e)
    {
        UpdateLayout();
        IsSelected = false;
    }

    private void SearchEntry_Unfocused(object sender, FocusEventArgs e)
    {
        Container.HeightRequest = 50;
        Container.ForceLayout();
    }

    private void SuggestionsListView_ItemSelected(object sender, ItemTappedEventArgs e)
    {
        IsSelected = true;
        SearchEntry.Text = !string.IsNullOrEmpty(DisplayPropertyName) ? e.Item?.GetType()?.GetRuntimeProperty(DisplayPropertyName)?.GetValue(e.Item)?.ToString() : e.Item?.ToString();
        Container.HeightRequest = 50;
        Container.ForceLayout();
    }

    private void OverlapContentView_Tapped(object sender, TappedEventArgs e)
    {
        UpdateLayout();
        IsSelected = false;

     }

    private int getExpectedHeight()
    {
        var items = SuggestionsListView.ItemsSource as IList;
        int wrapperHeightRequest = items != null ?
            (items.Count >= MaximumVisibleSuggestionItems ? MaximumVisibleSuggestionItems * 40 : items.Count * 40) : 0;
        if (Device.OS == TargetPlatform.Android)
        {
            return wrapperHeightRequest + 50;
        }
        return MaximumVisibleSuggestionItems * 40 + 50;
    }

    public AutoCompleteView()
    {
        Container = new Grid();
        SearchEntry = new Entry();
        SuggestionsListView = new ItemsStack();
        SuggestionWrapper = new NestedScrollView();

        // init Grid Layout
        Container.RowSpacing = 0;
        Container.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
        Container.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Star });
        Container.RowDefinitions.Add(new RowDefinition() { Height = 50 });
        Container.HeightRequest = 50;

        // init Search Entry
        SearchEntry.HorizontalOptions = LayoutOptions.Fill;
        SearchEntry.VerticalOptions = LayoutOptions.Fill;
        SearchEntry.TextChanged += SearchEntry_TextChanged;
        SearchEntry.Unfocused += SearchEntry_Unfocused;
        SearchEntry.Focused += SearchEntry_Focused;

        // init Suggestions ListView
        SuggestionsListView.BackgroundColor = Color.White;
        SuggestionsListView.ItemTapped += SuggestionsListView_ItemSelected;
        SuggestionsListView.VerticalOptions = LayoutOptions.End;
        SuggestionsListView.Spacing = 1;

        // suggestions Listview's wrapper
        SuggestionWrapper.VerticalOptions = LayoutOptions.Fill;
        SuggestionWrapper.Orientation = ScrollOrientation.Vertical;
        SuggestionWrapper.BackgroundColor = Color.White;
        SuggestionWrapper.Content = SuggestionsListView;

        Container.Children.Add(SuggestionWrapper);
        Container.Children.Add(SearchEntry, 0, 1);

        this.Content = Container;
    }
}

Exemple d'utilisation:

<customControls:AutoCompleteView SearchText="{Binding User.UniversitySchool}" Suggestions="{Binding Schools}" DisplayPropertyName="Name" Placeholder="Please choose your school">
                    <customControls:AutoCompleteView.SuggestionItemTemplate>
                        <DataTemplate>
                            <ContentView Padding="10">
                                <Label Text="{Binding Name}" HeightRequest="20" LineBreakMode="HeadTruncation" Style="{StaticResource MainContentLabel}" />
                            </ContentView>
                        </DataTemplate>
                    </customControls:AutoCompleteView.SuggestionItemTemplate>
                </customControls:AutoCompleteView>

Dans cette vue, j'ai utilisé le contrôle ItemStack. Vous pouvez vous référer à ceci: https://Gist.github.com/NVentimiglia/2723411428cdbb72fac6

2
Quý Nguyễn Nam

J'ai un contrôle personnalisé Xamarin.Forms que vous pouvez utiliser et qui fonctionne avec iOS, Android et UWP. Il utilise des rendus personnalisés pour fournir une interface utilisateur native sous les couvertures. J'ai construit cela parce que je n'ai trouvé aucun contrôle offrant une bonne expérience native et que je n'ai pas modifié la hauteur du contrôle à l'ouverture du menu déroulant . Toute la référence doc + du paquet NuGet est disponible ici: https://github.com/dotMorten/XamarinFormsControls/tree/master/AutoSuggestBox

1
dotMorten

Veuillez lire ces articles et essayer d'implémenter la solution sur Xamarin.Forms à l'aide de moteurs de rendu personnalisés.

API Google Place avec saisie semi-automatique sous Xamarin Android

Xamarin.iOS Location, saisie semi-automatique à l'aide de l'API Google Place

1
Tomasz Kowalczyk

J'ai essayé de construire mes propres suggestions/autocomplete suivant la réponse de Imdad. Mes critères me gênaient: il fallait que ce soit affiché en haut ou agrandi lorsque les suggestions remplissaient la liste. Pas de listview occupant de l'espace de façon permanente.

Vous pouvez essayer https://github.com/XamFormsExtended/Xfx.Controls Mais j'ai eu quelques problèmes avec. Il affiche sur le dessus

J'ai rencontré un problème où le texte dans autocompleteview ne se met pas à jour depuis la liaison de source ou le code derrière avec https://github.com/XLabs/Xamarin-Forms-Labs autocompleteview. Cela repousse temporairement ce qui est dans la manière d'afficher des suggestions

J'ai personnellement choisi cette solution https://github.com/dotMorten/XamarinFormsControls/tree/master/AutoSuggestBox

0
lolelo

Vous pouvez y parvenir facilement avec le plugin SyncFusion AutoComplete. Cela vous donne diverses options à faire plutôt que de faire un rendu personnalisé.

Référence: https://help.syncfusion.com/xamarin/sfautocomplete/getting-started

0