Xamarin Forms -  Recursos do Shell - IV
 Neste artigo vou continuar apresentando os recursos do Shell introduzido na versão 4.0 do Xamarin Forms,

Continuando o artigo anterior vamos agora implementar a pesquisa do Shell em nosso projeto.

O Shell do Xamarin.Forms fornecendo um manipulador de pesquisa integrado que permite economizar tempo de desenvolvimento.

Com uma caixa de pesquisa que pode ser adicionada ao topo de cada página, a consulta de pesquisa é manipulada pelo SearchHandler personalizado que processa a fonte de dados subjacente e retorna os resultados de volta à caixa de pesquisa e os exibe em uma lista pop-up.

A funcionalidade de pesquisa pode ser adicionada a uma página definindo a propriedade anexada Shell.SearchHandler como um objeto SearchHandler da subclasse. Isso faz com que uma caixa de pesquisa seja adicionada na parte superior da página.

Quando uma consulta é inserida na caixa de pesquisa, a propriedade Query é atualizada e, em cada atualização, o método OnQueryChanged é executado. Esse método pode ser substituído para preencher a área de sugestões de pesquisa com dados.

Em seguida, quando um resultado é selecionado na área de sugestões de pesquisa, o método OnItemSelected é executado. Esse método pode ser substituído para responder apropriadamente, por exemplo, navegando para uma página de detalhes.

Criando e consumindo um SearchHandler

Para criar o recurso de pesquisa integrada podemos criar subclasses da classe SearchHandler e substituir os métodos OnQueryChanged e OnItemSelected.

Vamos criar uma pasta Controls a classe AnimalSearchHandler que herda de SearchHandler, e, com base no código definido na documentação neste link, vamos incluir o código abaixo nesta classe:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using XF_ShellApp.Model;

namespace XF_ShellApp.Controls
{
    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);
            await Task.Delay(1000);

            ShellNavigationState state = (App.Current.MainPage as Shell).CurrentState;
            // Nota: strings serão codificadas para navegacao
            // (ex: "Blue Monkey" vira "Blue%20Monkey").

            await Shell.Current.GoToAsync($"{GetNavigationTarget()}?name={((Animal)item).Name}");
        }

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

A sobrescrita do método OnQueryChanged tem dois argumentos:

  1. oldValue, que contém a consulta de pesquisa anterior;
  2. newValue, que contém a consulta de pesquisa atual;

A área de sugestões de pesquisa pode ser atualizada, definindo-se a propriedade SearchHandler.ItemsSource como uma coleção IEnumerable que contém itens que correspondem à consulta de pesquisa atual.

Quando um resultado da pesquisa for selecionado pelo usuário, a sobrescrita do método OnItemSelected é executada e a propriedade SelectedItem é configurada. Neste exemplo, o método navega para outra página que exibe dados sobre o Animal selecionado.

Agora podemos consumir este SearchHandler que implementamos definindo a propriedade anexada Shell.SearchHandler para um objeto do tipo da subclasse.

Em nosso exemplo vamos incluir o código abaixo nas Views : Caes.xaml, Gatos.xaml e Outros.xaml.

Para a view Caes.xaml temos o código definido a seguir:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:data="clr-namespace:XF_ShellApp.Data"
             xmlns:data="clr-namespace:XF_ShellApp.Views"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:controls="clr-namespace:XF_ShellApp.Controls"
             mc:Ignorable="d"
             x:Class="XF_ShellApp.Views.Caes">
    <Shell.SearchHandler>
      <controls:AnimalSearchHandler Placeholder="Entre critério de busca"
                                ShowsResults="true"
                                ItemTemplate="{StaticResource AnimalSearchTemplate}"
                                Animals="{x:Static data:CachorrosData.Cachorros}"
                                SelectedItemNavigationTarget="{x:Type views:CaoDetailPage}" />
    </Shell.SearchHandler>
    <CollectionView Margin="20"
                    ItemsSource="{x:Static data:CachorrosData.Cachorros}"
                    ItemTemplate="{StaticResource AnimalTemplate}"
                    SelectionMode="Single"
                    SelectionChanged="OnCollectionViewSelectionChanged" />
</ContentPage>

Repetimos esse procedimento para as views Gatos.xaml e Outros.xaml.

Observe que estamos definindo a fonte de dados e a página de detalhes, que será diferente para cada view. (veja o código dos arquivos no projeto)

Definimos também um template comum para exibir os dados chamado AnimalSearchTemplate.

Podemos implementar este template no arquivo App.xaml conforme código abaixo:

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="XF_ShellApp.App">

    <Application.Resources>
        <DataTemplate x:Key="AnimalTemplate">
            <Grid Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Image Grid.RowSpan="2" 
                       Source="{Binding ImageUrl}" 
                       Aspect="AspectFill"
                       HeightRequest="80" 
                       WidthRequest="80" />
                <Label Grid.Column="1" 
                       Text="{Binding Name}" 
                       FontAttributes="Bold" />
                <Label Grid.Row="1"
                       Grid.Column="1" 
                       Text="{Binding Location}"
                       FontAttributes="Italic" 
                       VerticalOptions="End" />
            </Grid>
        </DataTemplate>
        <DataTemplate x:Key="AnimalSearchTemplate">
            <Grid Padding="10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.15*" />
                    <ColumnDefinition Width="0.85*" />
                </Grid.ColumnDefinitions>
                <Image Source="{Binding ImageUrl}" 
                       Aspect="AspectFill"
                       HeightRequest="40" 
                       WidthRequest="40" />
                <Label Grid.Column="1" 
                       Text="{Binding Name}" 
                       FontAttributes="Bold" />
            </Grid>
        </DataTemplate>        
    </Application.Resources>
</Application>

Definimos o template AnimalSearchTemplate que será usado como modelo de exibição dos dados.

Um último detalhe é que quando um SearchHandler é adicionado na parte superior de uma página, por padrão, a caixa de pesquisa fica visível e totalmente expandida.

Podemos alterar esse comportamento definindo a propriedade SearchHandler.SearchBoxVisibility como um dos membros da enumeração SearchBoxVisibility:

Agora é só alegria...

Executando o projeto iremos obter o seguinte resultado :

Pegue o código do projeto compartilhado aqui :  XF_ShellApp_4.zip  (sem as referências)

"Levantarei os meus olhos para os montes, de onde vem o meu socorro.
O meu socorro vem do Senhor que fez o céu e a terra."

Salmos 121:1,2

Referências:


José Carlos Macoratti