2016-07-17 240 views
7

Sono un novizio della piattaforma Xamarin.Forms. Spero che tu possa aiutarmi ad andare avanti. Voglio avere un controllo come completamento automatico in xamarin.forms come qui di seguitoXamarin.Forms Autocomplete CrossPlatform

Autocomplete

Potete per favore guidi come può essere realizzabile in Xamarin.Forms? Voglio raggiungere con la voce di controllo

TIA

+1

Si prega di scrivere la prossima volta qualche codice che hai provato o anche alcune idee che hai per quello che vuoi ottenere. – Imdad

risposta

6

Non hai incluso cosa esattamente si vuole, solo una sorta di completamento automatico.

io bullet point il modo manuale per farlo, in generale, per un elenco di articoli:

  1. Utilizzare un TextBox per consentire all'utente di inserire il testo.
  2. Utilizzare un elenco per raccogliere tutti gli oggetti insieme alle loro proprietà di ricerca come l'oggetto Nome.
  3. Mentre l'utente digita qualcosa nel TextBox, l'app deve cercare nell'elenco la stringa inserita nel controllo TextBox.
  4. I suggerimenti dovrebbero essere visualizzati, in base al valore di stringa digitato, in un controllo ListView sotto il controllo TextBox.
  5. L'utente fa clic sull'elemento ListView, che è un suggerimento, e quindi esegue il completamento automatico prendendo l'oggetto Nome dall'elemento su cui si è fatto clic sul TextBox.

Un modo generale di eseguire il completamento automatico senza la procedura lunga e approssimativa di cui sopra consiste nell'utilizzare Android AutoCompleteTextView.

È ancora possibile utilizzare la logica di base per farlo in Xamarin Forms.

Look here per AutoCompleteTextView per Android. Look here, here e here per assistenza con Completamento automatico in Xamarin Forms.

+0

Sono passato attraverso AutoCompleteTextView ma non è disponibile il completamento automatico in Xamarin.iOS? Hai qualche opinione al riguardo. –

+0

@ManojSethi È lo stesso principio descritto nel modo manuale di farlo. Anche questi componenti sono disponibili in Xamarin.iOS. :) – Imdad

1

ho implementato un AutocompleteView nel mio progetto. Puoi riferirlo.

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

Esempio di utilizzo:

<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 questa prospettiva, ho usato il controllo ItemStack. È possibile fare riferimento a questo: https://gist.github.com/NVentimiglia/2723411428cdbb72fac6

+0

Dove si trova NestedScrollView? È solo per Android o PCL? –

+0

Ah ... È necessario creare una vista personalizzata NestedScrollView e renderer per esso (solo Android). Quindi, si imposta l'attributo nativo NestedScrollingEnabled = true. (Consultare https://developer.xamarin.com/api/property/Android.Views.View.NestedScrollingEnabled/). Se non si dispone di questa classe, non è possibile scorrere l'elenco delle scelte del Completamento automatico. –

+0

@ Quý Nguyễn Nam, hai il codice per NestedScrollView – Wes