Android

11 fev, 2019

O X do Xamarin Forms — 4.0: CollectionView e CarouselView

Publicidade

Fala, galera! Beleza?

Acho que vocês já se cansaram de ler o quanto eu falo que o Xamarin.Forms é incrível, não é? Bom, eu não cansei de escrever.

Esse framework tem uma curva de evolução muito bacana, e nos últimos meses tem tido releases a cada 15 dias (em média), com funcionalidades úteis e muitas coisas que antes tínhamos que resolver no custom renderer.

Pois bem, agora, enquanto você lê (supondo que está lendo no dia da publicação), está em desenvolvimento a versão 4.0, trazendo novas funcionalidades incríveis (meu logo também vai pro 4.0)!

Tentarei trazer algumas dessas funcionalidades pra vocês terem um gostinho do que vem por aí, então nada mais justo do que começar com uma das que mais gostei: a incrível Collection View e CarouselView!

Vamos ver?

Observação: até o dia em que escrevi este artigo (29/01/2019), o Xamarin.Forms 4.0 estava em pré-release! Ou seja, algumas correções e alterações podem ser feitas atá a versão final. Não recomendo que seja utilizado em produção.

A ideia do CollectionView é ser um sucessor do ListView, com aprimoramentos de design, permitindo mais flexibilidade de layout e novas funções. Além disso, temos o novo CarouselView, que há muito tempo é aguardado (funcionando) em Xamarin.Forms.

Aviso: hoje o CarouselView “oficial” da Xamarin não funciona muito bem. Porém, caso precisem, recomendo este controle.

Configurando o projeto

Antes de entrar nas funcionalidades em si, precisamos configurar o Xamarin.Forms 4.0 pré-release.

Para isso, vamos ao nuget atualizar todos os nossos projetos para o Xamarin.Forms 4.0-pre:

Beleza! Agora precisaremos habilitar um flag no projeto iOS e Android:

global::Xamarin.Forms.Forms.SetFlags(“CollectionView_Experimental”);

iOS AppDelegate.cs:

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
   global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
   global::Xamarin.Forms.Forms.Init();
   LoadApplication(new App());

   return base.FinishedLaunching(app, options);
}

Android MainActivity.cs:

protected override void OnCreate(Bundle savedInstanceState)
{
   TabLayoutResource = Resource.Layout.Tabbar;
   ToolbarResource = Resource.Layout.Toolbar;

   base.OnCreate(savedInstanceState);

   global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
   global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
   LoadApplication(new App());
}

Fiquem tranquilos, esse flag é apenas da versão pré-release. A oficial não vai precisar.

Novidades da CollectionView

Antes de tudo, para facilitar os exemplos criaremos uma Model e ViewModel com alguns dados de teste:

 public class Game
    {
        public string Nome { get; set; }
        public string TituloBR { get; set; }
    }
 public class MainViewModel : INotifyPropertyChanged
    {
        #region Property

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(storage, value))
            {
                return false;
            }

            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }

        #endregion

        public ObservableCollection<Game> Games { get; }

        private int _rating;
        public int Rating
        {
            get { return _rating; }
            set => SetProperty(ref _rating, value);
        }

        public MainViewModel()
        {
            Games = new ObservableCollection<Game>();

            Games.Add(new Game
            {
                Nome = "God of War",
                TituloBR = "O bom da guerra"
            });

            Games.Add(new Game
            {
                Nome = "The last of us",
                TituloBR = "Nois que sobramus"
            });

            Games.Add(new Game
            {
                Nome = "Mario Kart 8",
                TituloBR = "Correndo com meus Amig..Inimigos"
            });

            Games.Add(new Game
            {
                Nome = "Super Mario Odyssey",
                TituloBR = "As viagens do Bigode"
            });

            Games.Add(new Game
            {
                Nome = "Halo",
                TituloBR = "E eu passei metiolate"
            });

        }

    }

Pronto! Agora podemos começar a brincadeira.

Um novo layout

Uma das primeiras coisas que podemos notar é a ausência do ViewCell.

O novo modelo proporciona ganhos de perfomance, principalmente no Android.

Se você reparar bem, o novo formato é parecido com o antigo, inclusive na utilização do DataTemplate:

<?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:local="clr-namespace:CollectionViewExemplo" 
             x:Class="CollectionViewExemplo.MainPage" Title="Nova CollectionView">
    
   <StackLayout>
        <CollectionView x:Name="cvGames" 
                        ItemsSource="{Binding Games}" 
                        Margin="10,0,0,0">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout HeightRequest="50" WidthRequest="200" Orientation="Vertical" Padding="0,5,0,5">
                        <Label Text="{Binding Nome}" FontAttributes="Bold"/>
                        <Label Text="{Binding TituloBR}" TextColor="Red" />
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage>

Rodando:

Bem simples, não? Creio que se você estava acostumado com o ListView, o novo collection não será um problema.

De baixo para cima, da esquerda para a direita: Grid Layout

Quando utilizamos o ListView estamos acostumados em uma lista vertical. Existiam controles customizados para resolver isso, como o FlowListView e o DynamicLayout.

Porém, agora é possível definir a orientação da CollectionView, o que me lembra do GridItemsLayout.

Podemos customizar nosso CollectionView para ficar com uma aparência mais profissional, além de ser possível fazer ele rolar para o lado. Incrível, não?

Veja a implementação abaixo:

    <StackLayout>
      <CollectionView x:Name="cvGames" ItemsSource="{Binding Games}"  Margin="10,0,10,600">
          <CollectionView.ItemsLayout>
              <GridItemsLayout Orientation="Horizontal" Span="2"/>
          </CollectionView.ItemsLayout>
          <CollectionView.ItemTemplate>
              <DataTemplate>
                  <Frame BorderColor="Red" CornerRadius="3" HasShadow="False" >
                      <Grid>
                          <Grid.ColumnDefinitions>
                              <ColumnDefinition Width="100"/>
                              <ColumnDefinition Width="100" />
                          </Grid.ColumnDefinitions>
                          <Grid.RowDefinitions>
                              <RowDefinition Height="Auto"/>
                          </Grid.RowDefinitions>
                          <Label Grid.Column="0" Text="{Binding Nome}"  FontAttributes="Bold"/>
                          <Label Grid.Column="1" Text="{Binding TituloBR}" />
                      </Grid>
                  </Frame>
              </DataTemplate>
          </CollectionView.ItemTemplate>
      </CollectionView>
  </StackLayout>

Podemos utilizar o Grid no template definindo a orientação para horizontal, e o Span para 2, assim podemos criar duas linhas e fazer a lista andar para o lado:

Tudo isso do próprio controle, sem a necessidade de implementações de terceiros.

A nova collection view suporta:

  • GridItemsLayout Horizontal
  • GridItemsLayout Vertical
  • ListItemsLayout Horizontal
  • ListItemsLayout Vertical

Tá vazio?

Você não tem itens para exibir? Isso não é um problema! Agora existe uma simples propriedade para isso, a CollectionView.EmptyView:

<CollectionView.EmptyView>
   <Label Text="Não temos games para Exibir :("/>
</CollectionView.EmptyView>

Então, se o source estiver vazio:

No exemplo utilizei um Label, mas você pode utilizar praticamente qualquer controle, exibindo uma imagem, por exemplo.

Finalmente! CarouselView

Talvez não seja correto escrever, mas sim, sentir.

CarouselView é algo muito esperado, pois podemos exibir os dados no bom e velho estilo cartão, com uma simples implementação:

 <CarouselView  x:Name="cvGames"
                    ItemsSource="{Binding Games}" 
                    HeightRequest="200" 
                    HorizontalOptions="Center" 
                    VerticalOptions="CenterAndExpand" 
                    Margin="10">
        <CarouselView.ItemsLayout>
            <GridItemsLayout Orientation="Horizontal"/>
        </CarouselView.ItemsLayout>
            <CarouselView.ItemTemplate>
                <DataTemplate>
                    <Frame BorderColor="Red" CornerRadius="3" HasShadow="False">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                      <ColumnDefinition Width="100"/>
                                      <ColumnDefinition Width="100" />
                                  </Grid.ColumnDefinitions>
                                  <Grid.RowDefinitions>
                                      <RowDefinition Height="Auto"/>
                                  </Grid.RowDefinitions>
                                  <Label Grid.Column="0" Text="{Binding Nome}"  FontAttributes="Bold"/>
                                  <Label Grid.Column="1" Text="{Binding TituloBR}" />
                              </Grid>
                    </Frame>
                </DataTemplate>
            </CarouselView.ItemTemplate>
        </CarouselView>
        <StackLayout VerticalOptions="StartAndExpand">
                <Slider Minimum="0" Maximum="4" ValueChanged="Slider_ValueChanged" MinimumTrackColor="#01579b" MaximumTrackColor="#01579b" ThumbColor="#9575cd"/>
        </StackLayout>

Coloquei um slider para mover o carousel:

Muito louco, né?

Aviso: em alguns testes tive alguns bugs com o iOS, mas é preview ainda. Até a versão final estará corrigido.

Snap, pare agora

Pra fechar, é possível configurar pontos de “Snap”. Com essa nova propriedade é possível fazer com que apenas um cartão apareça no centro por vez.

Para isso, basta adicionar as propriedades SnapPointsAlignment e SnapPointsType como abaixo:

 <GridItemsLayout Orientation="Horizontal"
   SnapPointsAlignment="Center" 
   SnapPointsType="Mandatory"/>

Com isso, ele centraliza automaticamente:

Mais fácil impossível.

Ufa, quanta coisa, hein? O que eu posso dizer é que o Xamarin.Forms 4.0 vai mudar muita coisa e facilitar a nossa vida criando apps. Isso porque eu não mostrei o Shell para vocês ainda, mas fica para um próximo artigo.

Caso queira baixar o código utilizado no exemplo, clique aqui.

Quer ver outros artigos sobre Xamarin? Basta acessar este link.

Espero ter ajudado. Aquele abraço!