Búsqueda en Xamarin.Forms Shell
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:
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:
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:
A medida que cambia la consulta de búsqueda, se actualiza el área de sugerencias de búsqueda:
Cuando se selecciona un resultado de la búsqueda, se navega a MonkeyDetailPage
y se muestra una página de detalles del mono seleccionado:
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:
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 propiedadSearchBoxVisibility
.
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únKeyboardFlags
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);