Búsqueda en Xamarin.Forms Shell

Download SampleDescargar el ejemplo

Xamarin.Forms Shell incluye la funcionalidad de búsqueda integrada que proporciona la clase SearchHandler. Se puede agregar funcionalidad de búsqueda a una página estableciendo la propiedad adjunta Shell.SearchHandler en un objeto SearchHandler con subclases. El resultado es un cuadro de búsqueda que se agrega en la parte superior de la página:

Screenshot of a Shell SearchHandler, on iOS and Android

Cuando se escribe una consulta en el cuadro de búsqueda, la propiedad Query se actualiza y, en cada actualización, se ejecuta el método OnQueryChanged. Este método se puede invalidar para rellenar el área de sugerencias de búsqueda con datos:

Screenshot of a search results in a Shell SearchHandler, on iOS and Android

Luego, cuando se seleccione un resultado del área de sugerencias de búsqueda, se ejecutará el método OnItemSelected. Este método se puede invalidar para responder de forma adecuada; por ejemplo, navegando a una página de detalles.

Creación de una clase SearchHandler

La funcionalidad de búsqueda se puede agregar a una aplicación de Shell mediante la creación de subclases de la clase SearchHandler y la invalidación de los métodos OnQueryChanged y OnItemSelected:

public class AnimalSearchHandler : SearchHandler
{
    public IList<Animal> Animals { get; set; }
    public Type SelectedItemNavigationTarget { get; set; }

    protected override void OnQueryChanged(string oldValue, string newValue)
    {
        base.OnQueryChanged(oldValue, newValue);

        if (string.IsNullOrWhiteSpace(newValue))
        {
            ItemsSource = null;
        }
        else
        {
            ItemsSource = Animals
                .Where(animal => animal.Name.ToLower().Contains(newValue.ToLower()))
                .ToList<Animal>();
        }
    }

    protected override async void OnItemSelected(object item)
    {
        base.OnItemSelected(item);

        // Let the animation complete
        await Task.Delay(1000);

        ShellNavigationState state = (App.Current.MainPage as Shell).CurrentState;
        // The following route works because route names are unique in this application.
        await Shell.Current.GoToAsync($"{GetNavigationTarget()}?name={((Animal)item).Name}");
    }

    string GetNavigationTarget()
    {
        return (Shell.Current as AppShell).Routes.FirstOrDefault(route => route.Value.Equals(SelectedItemNavigationTarget)).Key;
    }
}

La invalidación OnQueryChanged tiene dos argumentos: oldValue, que contiene la consulta de búsqueda anterior, y newValue, que contiene la consulta de búsqueda actual. El área de sugerencias de búsqueda se puede actualizar mediante el establecimiento de la propiedad SearchHandler.ItemsSource en una colección IEnumerable que contiene elementos que coinciden con la consulta de búsqueda actual.

Cuando el usuario selecciona un resultado de búsqueda, se ejecuta la invalidación OnItemSelected y se establece la propiedad SelectedItem. En este ejemplo, el método dirige a otra página que muestra datos sobre el elemento Animal seleccionado. Para obtener más información sobre la navegación, consulte Navegación en Xamarin.Forms Shell.

Nota:

Se pueden establecer propiedades SearchHandler adicionales para controlar la apariencia del cuadro de búsqueda.

Consumo de una clase SearchHandler

La clase SearchHandler con subclases se puede consumir mediante el establecimiento de la propiedad adjunta Shell.SearchHandler en un objeto del tipo con subclases, en la página de consumo:

<ContentPage ...
             xmlns:controls="clr-namespace:Xaminals.Controls">
    <Shell.SearchHandler>
        <controls:AnimalSearchHandler Placeholder="Enter search term"
                                      ShowsResults="true"
                                      DisplayMemberName="Name" />
    </Shell.SearchHandler>
    ...
</ContentPage>

El código de C# equivalente es el siguiente:

Shell.SetSearchHandler(this, new AnimalSearchHandler
{
    Placeholder = "Enter search term",
    ShowsResults = true,
    DisplayMemberName = "Name"
});

El método AnimalSearchHandler.OnQueryChanged devuelve un elemento List de objetos Animal. La propiedad DisplayMemberName se establece en la propiedad Name de cada objeto Animal, por lo que los datos mostrados en el área de sugerencias serán el nombre de cada animal.

La propiedad ShowsResults está establecida en true, de modo que se muestran sugerencias de búsqueda cuando el usuario escribe una consulta de búsqueda:

Screenshot of search results in a Shell SearchHandler, on iOS and Android, with results for the partial string M.

A medida que cambia la consulta de búsqueda, se actualiza el área de sugerencias de búsqueda:

Screenshot of search results in a Shell SearchHandler, on iOS and Android, with results for the partial string M o n.

Cuando se selecciona un resultado de la búsqueda, se navega a MonkeyDetailPage y se muestra una página de detalles del mono seleccionado:

Screenshot of monkey details, on iOS and Android

Definición de la apariencia de los elemento de los resultados de búsqueda

Además de mostrar datos de string en los resultados de la búsqueda, se puede definir la apariencia de cada uno de los elementos de los resultados de la búsqueda mediante el establecimiento de la propiedad SearchHandler.ItemTemplate en DataTemplate:

<ContentPage ...
             xmlns:controls="clr-namespace:Xaminals.Controls">    
    <Shell.SearchHandler>
        <controls:AnimalSearchHandler Placeholder="Enter search term"
                                      ShowsResults="true">
            <controls:AnimalSearchHandler.ItemTemplate>
                <DataTemplate>
                    <Grid Padding="10"
                          ColumnDefinitions="0.15*,0.85*">
                        <Image Source="{Binding ImageUrl}"
                               HeightRequest="40"
                               WidthRequest="40" />
                        <Label Grid.Column="1"
                               Text="{Binding Name}"
                               FontAttributes="Bold"
                               VerticalOptions="Center" />
                    </Grid>
                </DataTemplate>
            </controls:AnimalSearchHandler.ItemTemplate>
       </controls:AnimalSearchHandler>
    </Shell.SearchHandler>
    ...
</ContentPage>

El código de C# equivalente es el siguiente:

Shell.SetSearchHandler(this, new AnimalSearchHandler
{
    Placeholder = "Enter search term",
    ShowsResults = true,
    ItemTemplate = new DataTemplate(() =>
    {
        Grid grid = new Grid { Padding = 10 };
        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.15, GridUnitType.Star) });
        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.85, GridUnitType.Star) });

        Image image = new Image { HeightRequest = 40, WidthRequest = 40 };
        image.SetBinding(Image.SourceProperty, "ImageUrl");
        Label nameLabel = new Label { FontAttributes = FontAttributes.Bold, VerticalOptions = LayoutOptions.Center };
        nameLabel.SetBinding(Label.TextProperty, "Name");

        grid.Children.Add(image);
        grid.Children.Add(nameLabel, 1, 0);
        return grid;
    })
});

Los elementos especificados en DataTemplate definen la apariencia de cada elemento en el área de sugerencias. En este ejemplo, el diseño dentro de DataTemplate se administra mediante un objeto Grid. El objeto Grid contiene un objeto Image y un objeto Label, que enlazan ambos con las propiedades de cada objeto Monkey.

Las capturas de pantalla siguientes muestran el resultado de crear plantillas para cada elemento del área de sugerencias:

Screenshot of templated search results in a Shell SearchHandler, on iOS and Android

Para obtener más información sobre las plantillas de datos, consulte Plantillas de datos de Xamarin.Forms.

Visibilidad del cuadro de búsqueda

Cuando se agrega un objeto SearchHandler en la parte superior de una página, el cuadro de búsqueda está visible y totalmente expandido de forma predeterminada. Pero este comportamiento se puede cambiar estableciendo la propiedad SearchHandler.SearchBoxVisibility en uno de los miembros de la enumeración SearchBoxVisibility:

  • Hidden: el cuadro de búsqueda no es visible ni accesible.
  • Collapsible: el cuadro de búsqueda está oculto hasta que el usuario realiza una acción para mostrarlo. En iOS, el cuadro de búsqueda aparece rebotando verticalmente el contenido de la página y, en Android, el cuadro de búsqueda aparece al pulsar el icono del signo de interrogación.
  • Expanded: el cuadro de búsqueda está visible y totalmente expandido. Se trata del valor predeterminado de la propiedad SearchBoxVisibility.

Importante

En iOS, un cuadro de búsqueda contraíble requiere iOS 11 o superior.

En el ejemplo siguiente se muestra cómo ocultar el cuadro de búsqueda:

<ContentPage ...
             xmlns:controls="clr-namespace:Xaminals.Controls">
    <Shell.SearchHandler>
        <controls:AnimalSearchHandler SearchBoxVisibility="Hidden"
                                      ... />
    </Shell.SearchHandler>
    ...
</ContentPage>

Enfoque en el cuadro de búsqueda

Al pulsar en un cuadro de búsqueda aparece el teclado en pantalla, y el cuadro de búsqueda adquiere el foco de entrada. Esto también se consigue mediante programación llamando al método Focus, que intenta establecer el foco de entrada en el cuadro de búsqueda y, si se realiza correctamente, devuelve true. Cuando un cuadro de búsqueda obtiene el foco, se desencadena el evento Focused y se llama al método OnFocused reemplazable.

Cuando un cuadro de búsqueda tiene el foco de entrada, al pulsar en otro lugar en la pantalla desaparece el teclado en pantalla y el cuadro de búsqueda pierde el foco de entrada. Esto también se consigue mediante programación llamando al método Unfocus. Cuando un cuadro de búsqueda pierde el foco, se desencadena el evento Unfocused y se llama al método OnUnfocus reemplazable.

Se puede recuperar el estado del foco de un cuadro de búsqueda a través de la propiedad IsFocused, que devuelve true si un objeto SearchHandler tiene actualmente el foco de entrada.

Teclado SearchHandler

El teclado que aparece cuando los usuarios interactúan con un objeto SearchHandler se puede establecer mediante programación a través de la propiedad Keyboard en una de las siguientes propiedades de la clase Keyboard:

  • Chat: se usa para el texto y los lugares donde los emoji son útiles.
  • Default: el teclado predeterminado.
  • Email: se usa al especificar direcciones de correo electrónico.
  • Numeric: se usa al escribir números.
  • Plain: se usa al escribir texto, sin ningún KeyboardFlags especificado.
  • Telephone: se usa al escribir números de teléfono.
  • Text: se usa al escribir texto.
  • Url : se usa para especificar las rutas de acceso de archivo y direcciones web.

Esto se puede lograr en XAML de la siguiente manera:

<SearchHandler Keyboard="Email" />

El código de C# equivalente es el siguiente:

SearchHandler searchHandler = new SearchHandler { Keyboard = Keyboard.Email };

La clase Keyboard tiene también un patrón de diseño Factory Method Create que puede usarse para personalizar un teclado mediante la especificación del comportamiento de las mayúsculas y minúsculas, el corrector ortográfico y las sugerencias. Los valores de enumeración KeyboardFlags se especifican como argumentos para el método, con la devolución de un Keyboard personalizado. La enumeración KeyboardFlags contiene los valores siguientes:

  • None: no se agregan características al teclado.
  • CapitalizeSentence: indica que la primera letra de la primera palabra de cada frase se escribirá automáticamente en mayúsculas.
  • Spellcheck: indica que se pasará el corrector ortográfico al texto especificado.
  • Suggestions: indica que se ofrecerán finalizaciones de palabra para el texto especificado.
  • CapitalizeWord: indica que las primeras letras de todas las palabras se escribirán automáticamente en mayúsculas.
  • CapitalizeCharacter: indica que todos los caracteres se escribirán automáticamente en mayúsculas.
  • CapitalizeNone: indica que no se producirá ningún uso automático de mayúsculas.
  • All: indica que se pasará el corrector automático, se ofrecerán finalizaciones de palabras y las frases empezarán en mayúsculas en el texto especificado.

El ejemplo de código XAML siguiente muestra cómo personalizar el Keyboard predeterminado para ofrecer finalizaciones de palabras y poner en mayúsculas todos los caracteres especificados:

<SearchHandler Placeholder="Enter search terms">
    <SearchHandler.Keyboard>
        <Keyboard x:FactoryMethod="Create">
            <x:Arguments>
                <KeyboardFlags>Suggestions,CapitalizeCharacter</KeyboardFlags>
            </x:Arguments>
        </Keyboard>
    </SearchHandler.Keyboard>
</SearchHandler>

El código de C# equivalente es el siguiente:

SearchHandler searchHandler = new SearchHandler { Placeholder = "Enter search terms" };
searchHandler.Keyboard = Keyboard.Create(KeyboardFlags.Suggestions | KeyboardFlags.CapitalizeCharacter);