Hoje irei falar novamente sobre o CarouselView. Após o meu post CarouselView – Xamarin.Forms, algumas pessoas me procuraram perguntando como adicionar indicadores.
Indicadores são ícones de índice, com a finalidade de informar ao usuário que aquele elemento é uma lista, independente de qual conteúdo for, e a posição na qual ele se encontra.
Porém, no momento em que escrevo este post o componente do CarouselView não possui uma propriedade de indicadores, então você precisará implementá-la.
Para este exemplo, partirei do principio que você já criou o seu CarouselView, caso possua alguma dúvida sobre isso, recomendo ler o post CarouselView – Xamarin.Forms .
Ícones
Para este exemplo usei 2 ícones com círculos para utilizar de indicadores, sendo um deles preenchido na parte interior para informar o elemento corrente, e um círculo sem preenchimento para informar os demais elementos do CarouselView.
Selecionado
Não Selecionado
Adicione esses ícones nas pastas designadas para as imagens de acordo com cada plataforma, caso possua alguma dúvida na plataforma Android, recomendo ler o post Adicionando imagens em projeto Android – Xamarin.
Classe IndicadoresCarousel
Em seguida crie uma classe com o nome “IndicadoresCarousel.cs” para realizar o controle dos indicadores. Adicione o código a seguir na classe.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Linq; | |
using Xamarin.Forms; | |
namespace DemoCarouselView | |
{ | |
public class IndicadoresCarousel : Grid | |
{ | |
private ImageSource UnselectedImageSource = null; | |
private ImageSource SelectedImageSource = null; | |
private readonly StackLayout _indicators = new StackLayout() { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.CenterAndExpand }; | |
public IndicadoresCarousel() | |
{ | |
this.HorizontalOptions = LayoutOptions.CenterAndExpand; | |
this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); | |
this.Children.Add(_indicators); | |
} | |
public static readonly BindableProperty PositionProperty = BindableProperty.Create(nameof(Position), typeof(int), typeof(IndicadoresCarousel), 0, BindingMode.TwoWay, propertyChanging: PositionChanging); | |
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(IndicadoresCarousel), Enumerable.Empty<object>(), BindingMode.OneWay, propertyChanged: ItemsChanged); | |
public static readonly BindableProperty SelectedIndicatorProperty = BindableProperty.Create(nameof(SelectedIndicator), typeof(string), typeof(IndicadoresCarousel), "", BindingMode.OneWay); | |
public static readonly BindableProperty UnselectedIndicatorProperty = BindableProperty.Create(nameof(UnselectedIndicator), typeof(string), typeof(IndicadoresCarousel), "", BindingMode.OneWay); | |
public static readonly BindableProperty IndicatorWidthProperty = BindableProperty.Create(nameof(IndicatorWidth), typeof(double), typeof(IndicadoresCarousel), 0.0, BindingMode.OneWay); | |
public static readonly BindableProperty IndicatorHeightProperty = BindableProperty.Create(nameof(IndicatorHeight), typeof(double), typeof(IndicadoresCarousel), 0.0, BindingMode.OneWay); | |
public string SelectedIndicator | |
{ | |
get { return (string)this.GetValue(SelectedIndicatorProperty); } | |
set { this.SetValue(SelectedIndicatorProperty, value); } | |
} | |
public string UnselectedIndicator | |
{ | |
get { return (string)this.GetValue(UnselectedIndicatorProperty); } | |
set { this.SetValue(UnselectedIndicatorProperty, value); } | |
} | |
public double IndicatorWidth | |
{ | |
get { return (double)this.GetValue(IndicatorWidthProperty); } | |
set { this.SetValue(IndicatorWidthProperty, value); } | |
} | |
public double IndicatorHeight | |
{ | |
get { return (double)this.GetValue(IndicatorHeightProperty); } | |
set { this.SetValue(IndicatorHeightProperty, value); } | |
} | |
public int Position | |
{ | |
get { return (int)this.GetValue(PositionProperty); } | |
set { this.SetValue(PositionProperty, value); } | |
} | |
public IEnumerable ItemsSource | |
{ | |
get { return (IEnumerable)this.GetValue(ItemsSourceProperty); } | |
set { this.SetValue(ItemsSourceProperty, (object)value); } | |
} | |
private void Clear() | |
{ | |
_indicators.Children.Clear(); | |
} | |
private void Init(int position) | |
{ | |
if (UnselectedImageSource == null) | |
UnselectedImageSource = ImageSource.FromFile(UnselectedIndicator); | |
if (SelectedImageSource == null) | |
SelectedImageSource = ImageSource.FromFile(SelectedIndicator); | |
if (_indicators.Children.Count > 0) | |
{ | |
for (int i = 0; i < _indicators.Children.Count; i++) | |
{ | |
if (((Image)_indicators.Children[i]).ClassId == nameof(State.Selected) && i != position) | |
_indicators.Children[i] = BuildImage(State.Unselected, i); | |
else if (((Image)_indicators.Children[i]).ClassId == nameof(State.Unselected) && i == position) | |
_indicators.Children[i] = BuildImage(State.Selected, i); | |
} | |
} | |
else | |
{ | |
var enumerator = ItemsSource.GetEnumerator(); | |
int count = 0; | |
while (enumerator.MoveNext()) | |
{ | |
Image image = null; | |
if (position == count) | |
image = BuildImage(State.Selected, count); | |
else | |
image = BuildImage(State.Unselected, count); | |
_indicators.Children.Add(image); | |
count++; | |
} | |
} | |
} | |
private Image BuildImage(State state, int position) | |
{ | |
var image = new Image() | |
{ | |
WidthRequest = IndicatorWidth, | |
HeightRequest = IndicatorHeight, | |
ClassId = state.ToString() | |
}; | |
switch (state) | |
{ | |
case State.Selected: | |
image.Source = SelectedImageSource; | |
break; | |
case State.Unselected: | |
image.Source = UnselectedImageSource; | |
break; | |
default: | |
throw new Exception("Invalid state selected"); | |
} | |
image.GestureRecognizers.Add(new TapGestureRecognizer() { Command = new Command(() => { Position = position; }) }); | |
return image; | |
} | |
private static void PositionChanging(object bindable, object oldValue, object newValue) | |
{ | |
var carouselIndicators = bindable as IndicadoresCarousel; | |
carouselIndicators.Init(Convert.ToInt32(newValue)); | |
} | |
private static void ItemsChanged(object bindable, object oldValue, object newValue) | |
{ | |
var carouselIndicators = bindable as IndicadoresCarousel; | |
carouselIndicators.Clear(); | |
carouselIndicators.Init(0); | |
} | |
public enum State | |
{ | |
Selected, | |
Unselected | |
} | |
} | |
} |
https://gist.github.com/juucustodio/36b34a49c33301aae07e83a818a69221
C# Realizado no Code-Behind
Aproveitando o exemplo do post anterior, realizei o Binding no próprio Code-Behind para fins de demonstração dos indicadores, para isso no método construtor atribua “this” para o BindingContext, como demonstrado no exemplo a seguir:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.ComponentModel; | |
using Xamarin.Forms; | |
namespace DemoCarouselView | |
{ | |
public partial class IndicadoresPage : ContentPage, INotifyPropertyChanged | |
{ | |
public IndicadoresPage() | |
{ | |
InitializeComponent(); | |
ListaImagens = new List<string> | |
{ | |
"foto1.jpg", | |
"foto2.jpg", | |
"foto3.jpg" | |
}; | |
BindingContext = this; | |
} | |
public List<string> ListaImagens { get; set; } | |
private int _position; | |
public int Position { get { return _position; } set { _position = value; OnPropertyChanged(); } } | |
} | |
} |
Xaml
Na sua view, levando em consideração que você já adicionou o componente CarouselView conforme exemplificado no post anterior, adicione os indicadores como demonstrado a seguir:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8" ?> | |
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" | |
xmlns:local="clr-namespace:DemoCarouselView" | |
xmlns:forms="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView" | |
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | |
x:Class="DemoCarouselView.IndicadoresPage"> | |
<StackLayout> | |
<forms:CarouselView x:Name="ImageCarouselView" Position="{Binding Position, Mode=TwoWay}" | |
ItemsSource="{Binding ListaImagens}" > | |
<forms:CarouselView.ItemTemplate> | |
<DataTemplate> | |
<Image Source="{Binding .}"/> | |
</DataTemplate> | |
</forms:CarouselView.ItemTemplate> | |
</forms:CarouselView> | |
<local:IndicadoresCarousel x:Name="Indicadores" IndicatorHeight="16" IndicatorWidth="16" | |
UnselectedIndicator="naoSelecionado.png" SelectedIndicator="selecionado.png" | |
Position="{Binding Position}" ItemsSource="{Binding ListaImagens}" /> | |
</StackLayout> | |
</ContentPage> |
Resultado
Esse e todos os exemplos deste blog encontram-se disponíveis no GitHub.
Tem como colocar, passar texto na label?
CurtirCurtir
Olá Wanderson, você diz utilizar uma label ao invés de uma Image ? Se for isso… sim.
CurtirCurtir