web-dev-qa-db-de.com

Xamarin.Forms Autocomplete Cross Platform

Ich bin ein Neuling in der Xamarin.Forms-Plattform. Ich hoffe, Sie können mir helfen, weiterzukommen. Ich möchte ein Steuerelement wie Autocomplete in xamarin.forms wie unten 

 Autocomplete

Können Sie uns bitte erklären, wie es in Xamarin.Forms erreichbar ist? Ich möchte es mit dem Entry Control erreichen

TIA

8
Manoj Sethi

Sie haben nicht genau das aufgenommen, was Sie möchten, sondern nur eine Art Autovervollständigung.

Ich führe die manuelle Vorgehensweise an, um es allgemein für eine Liste von Elementen zu tun:

  1. Verwenden Sie ein Textfeld, damit der Benutzer Text eingeben kann.
  2. Verwenden Sie eine Liste, um alle Ihre Objekte zusammen mit ihrer durchsuchbaren Eigenschaft, z. B. dem Objektnamen, zusammenzustellen.
  3. Wenn der Benutzer etwas in das Textfeld eingibt, sollte die App in der Liste nach dem in das Textfeld eingegebenen String suchen.
  4. Die Vorschläge sollten entsprechend dem eingegebenen String-Wert in einer ListView unter der TextBox angezeigt werden.
  5. Der Benutzer klickt auf das ListView-Element. Dies ist ein Vorschlag. Anschließend wird der Name des Objekts automatisch aus dem angeklickten Element in das Textfeld übernommen.

Eine allgemeine Möglichkeit, die Autovervollständigung ohne das lange, grobe Verfahren durchzuführen, ist die Verwendung von Android AutoCompleteTextView.

Sie können immer noch die grundlegende Logik verwenden, um dies in Xamarin Forms zu tun.

Schauen Sie hier nach dem AutoCompleteTextView für Android . Schauen Sie hier , hier und hier nach Hilfe mit AutoComplete in Xamarin Forms.

8
Imdad

Ich habe in meinem Projekt eine AutocompleteView implementiert. Sie können es verweisen.

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

Anwendungsbeispiel:

<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>

In dieser Ansicht habe ich das ItemStack-Steuerelement verwendet. Sie können dies verweisen: https://Gist.github.com/NVentimiglia/2723411428cdbb72fac6

2

Ich habe ein benutzerdefiniertes Xamarin.Forms-Steuerelement, das mit iOS, Android und UWP funktioniert. Es verwendet benutzerdefinierte Renderer, um eine native Benutzeroberfläche unter den Deckblättern bereitzustellen. Ich habe dies erstellt, weil ich kein Steuerelement gefunden habe, das eine gute native Erfahrung bietet und die Höhe des Steuerelements nicht geändert hat, wenn das Dropdown-Menü geöffnet wird ..__ Alle doc + -Referenzen für das NuGet-Paket finden Sie hier: . https://github.com/dotMorten/XamarinFormsControls/tree/master/AutoSuggestBox

1
dotMorten

Bitte lesen Sie diese Artikel und versuchen Sie, die Lösung mit benutzerdefinierten Renderern auf Xamarin.Forms zu implementieren.

Google Place-API mit Autocomplete in Xamarin Android

Xamarin.iOS Location Autocomplete mithilfe der Google Place-API

1

Ich benutze diese Bibliothek SupportWidgetXF

Es ist plattformübergreifend.

0
MrL

Ich habe versucht, nach der Antwort von Imdad eigene Vorschläge/Autocomplete zu erstellen. Ich wurde durch meine Kriterien behindert, bei denen es oben angezeigt oder erweitert werden musste, wenn Vorschläge die Listenansicht füllten. Keine Listenansicht, die permanent Speicherplatz beansprucht.

Sie können versuchen, https://github.com/XamFormsExtended/Xfx.Controls Ich habe jedoch einige Probleme damit. Es wird oben angezeigt

Es ist ein Problem aufgetreten, bei dem Text in autocompleteview nicht von der Quellbindung aktualisiert oder im Code hinter mit https://github.com/XLabs/Xamarin-Forms-Labs autocompleteview festgelegt wird. Dadurch wird das, was zeitweise im Weg ist, Vorschläge weggeschoben

Ich persönlich ging diese Lösung https://github.com/dotMorten/XamarinFormsControls/tree/master/AutoSuggestBox

0
lolelo

Mit dem SyncFusion AutoComplete-Plugin können Sie dies problemlos erreichen. Dadurch haben Sie verschiedene Optionen, anstatt ein benutzerdefiniertes Rendering durchzuführen.

Referenz: https://help.syncfusion.com/xamarin/sfautocomplete/getting-started