[Xamarin.Forms] Descubriendo el control Expander


Hace pocos días se lanzó Xamarin.Forms 4.6 por el canal estable y con esta versión llega Expander un control que tenia muchas ganas de probar, he preparado un pequeño ejemplo para enseñar lo sencillo que es de utilizar y el resultado es espectacular, con este control puedes dar a tus aplicaciones un toque más dinámico en términos visuales, empecemos con el ejemplo:

El único requisito que necesitas para usar este control es tener de la versión 4.6-pre4 de Xamarin.Forms en adelante.

Primero que nada crearemos un modelo del objeto que utilizaremos en este ejemplo, en este caso se llamara Person y tendrá unas propiedades básicas:
    public class Person
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
        public string Icon { get; set; }
    }
Ahora crearemos en el view model de nuestra vista un observable collection que contendrá objetos de tipo Person:
    private ObservableCollection<Person> _persons = new ObservableCollection<Person>();

    public ObservableCollection<Person> Persons
    {
        get => _persons;
        set
        {
            _persons = value;
            RaiseOnPropertyChanged();
        }
    }
Vamos a inicializar esa lista en el constructor del view model con algunos objetos de prueba:
    public PersonsHomeViewModel()
    {
        InitializePersons();
    }

    private void InitializePersons()
    {
        for (var i = 0; i < 50; i++)
        {
            var newPerson = new Person
            {
                Name = $"Name {i}",
                Surname = $"Surname {i}",
                Email = $"email{i}@outlook.com",
                Phone = $"Phone: {i}",
                Icon = "woman"
            };

            if (i % 2 == 0)
            {
                newPerson.Icon = "man";
            }
            Persons.Add(newPerson);
        }
    }
Una vez tenemos la lógica de la aplicación definida ya podemos empezar a diseñar nuestra vista, crearemos un collection view en el cual bindearemos en su propiedad ItemsSource el observable collection (Persons) que hemos creado anteriormente en nuestro view model:
    <CollectionView ItemsSource="{Binding Persons}"
                    Margin="10,10,10,10"
                    SelectionMode="None"  
                    HorizontalOptions="FillAndExpand"
                    VerticalOptions="FillAndExpand"
                    VerticalScrollBarVisibility="Always">
        <CollectionView.ItemTemplate>
            <DataTemplate>

            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

Aquí entra en acción Expander, en el DataTemplate de nuestro collection view vamos a declarar el control Expander en el cual definiremos las siguientes propiedades: ExpandAnimationEasing que es la animación que se produce cuando Expander se expande y CollapseAnimationEasing que es la animación que se produce cuando Expander se colapsa, en ambas propiedades utilizaremos la animación Easing.Linear, por ultimo añadiremos la propiedad IsExpanded de tipo bool, que determina si Expander se expande. Esta propiedad utiliza el TwoWay como modo de enlace y tiene como valor predeterminado false. Ahora como podemos observar tenemos el header que es lo que Expander mostrara por defecto cuando no esté expandido:
    <Expander ExpandAnimationEasing="{x:Static Easing.Linear}"
              CollapseAnimationEasing="{x:Static Easing.Linear}"
              IsExpanded="{Binding IsDetailVisible, Mode=TwoWay}">
        <Expander.Header>
            <!--Contenido de la cabecera-->
        </Expander.Header>
        <!--Contenido del cuerpo-->
    </Expander>
En el header mostraremos las propiedades Name, Surname y Icon del objeto Person, para ello usaremos un Frame y un StackLayout para envolver el contenido y dar un toque visual más agradable, mostraremos el Name y el Surname de las personas en un solo Label beneficiándonos del uso de FormattedText y el StackLayout tendrá una orientación horizontal para mostrar el icono y el label uno al lado del otro:
    <Frame HasShadow="False"
           Margin="10,10,0,0"
           BorderColor="#ECECEC"
           BackgroundColor="White"
           HorizontalOptions="FillAndExpand"
           VerticalOptions="FillAndExpand">
        <StackLayout Orientation="Horizontal">
            <Image Source="{Binding Icon}"
                   HorizontalOptions="Center"
                   VerticalOptions="Start"
                   HeightRequest="50"
                   WidthRequest="50"/>
            <Label HorizontalOptions="Start"
                   VerticalOptions="Start"
                   TextColor="Black"
                   FontSize="Medium">
                <Label.FormattedText>
                    <FormattedString>
                        <Span Text="{Binding Name}" />
                        <Span Text=" " />
                        <Span Text="{Binding Surname}" />
                    </FormattedString>
                </Label.FormattedText>
            </Label>
        </StackLayout>
    </Frame>
Ahora diseñaremos el cuerpo del Expander que se mostrará cada vez que se expanda, aquí mostraremos las propiedades restantes de Person, en este caso Email y Phone y también pondremos unos iconos para que sea más visual:
    <Frame HasShadow="False"
           Margin="10,10,0,20"
           BorderColor="#ECECEC"
           BackgroundColor="White"
           HorizontalOptions="FillAndExpand"
           VerticalOptions="FillAndExpand">
        <Grid HorizontalOptions="FillAndExpand"
              VerticalOptions="FillAndExpand">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Image Grid.Row ="0"
                   Grid.Column="0"
                   Source="email"
                   HorizontalOptions="StartAndExpand"
                   VerticalOptions="Start"
                   HeightRequest="20"
                   WidthRequest="20"/>
            <Label Grid.Row ="0"
                   Grid.Column="1"
                   Text="{Binding Email}"
                   HorizontalOptions="StartAndExpand"
                   VerticalOptions="Start"
                   TextColor="Black"
                   FontSize="Medium"/>
            <Image Grid.Row ="2"
                   Grid.Column="0"
                   Source="phone"
                   HorizontalOptions="StartAndExpand"
                   VerticalOptions="Start"
                   HeightRequest="20"
                   WidthRequest="20"/>
            <Label Grid.Row ="2"
                   Grid.Column="1"
                   Text="{Binding Phone}"
                   HorizontalOptions="StartAndExpand"
                   VerticalOptions="Start"
                   TextColor="Black"
                   FontSize="Medium"/>
        </Grid>
    </Frame>

Una vez que hayamos añadido el header y el cuerpo del Expander, nuestro collection view quedaría así:
    <CollectionView ItemsSource="{Binding Persons}"
                    Margin="10,10,10,10"
                    SelectionMode="None"  
                    HorizontalOptions="FillAndExpand"
                    VerticalOptions="FillAndExpand"
                    VerticalScrollBarVisibility="Always">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <Expander ExpandAnimationEasing="{x:Static Easing.Linear}"
                          CollapseAnimationEasing="{x:Static Easing.Linear}"
                          IsExpanded="{Binding IsDetailVisible, Mode=TwoWay}">
                    <Expander.Header>
                        <Frame HasShadow="False"
                               Margin="10,10,0,0"
                               BorderColor="#ECECEC"
                               BackgroundColor="White"
                               HorizontalOptions="FillAndExpand"
                               VerticalOptions="FillAndExpand">
                            <StackLayout Orientation="Horizontal">
                                <Image Source="{Binding Icon}"
                                       HorizontalOptions="Center"
                                       VerticalOptions="Start"
                                       HeightRequest="50"
                                       WidthRequest="50"/>
                                <Label HorizontalOptions="Start"
                                       VerticalOptions="Start"
                                       TextColor="Black"
                                       FontSize="Medium">
                                    <Label.FormattedText>
                                        <FormattedString>
                                            <Span Text="{Binding Name}" />
                                            <Span Text=" " />
                                            <Span Text="{Binding Surname}" />
                                        </FormattedString>
                                    </Label.FormattedText>
                                </Label>
                            </StackLayout>
                        </Frame>
                    </Expander.Header>
                    <Frame HasShadow="False"
                           Margin="10,10,0,20"
                           BorderColor="#ECECEC"
                           BackgroundColor="White"
                           HorizontalOptions="FillAndExpand"
                           VerticalOptions="FillAndExpand">
                        <Grid HorizontalOptions="FillAndExpand"
                              VerticalOptions="FillAndExpand">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>

                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <Image Grid.Row ="0"
                                   Grid.Column="0"
                                   Source="email"
                                   HorizontalOptions="StartAndExpand"
                                   VerticalOptions="Start"
                                   HeightRequest="20"
                                   WidthRequest="20"/>
                            <Label Grid.Row ="0"
                                   Grid.Column="1"
                                   Text="{Binding Email}"
                                   HorizontalOptions="StartAndExpand"
                                   VerticalOptions="Start"
                                   TextColor="Black"
                                   FontSize="Medium"/>
                            <Image Grid.Row ="2"
                                   Grid.Column="0"
                                   Source="phone"
                                   HorizontalOptions="StartAndExpand"
                                   VerticalOptions="Start"
                                   HeightRequest="20"
                                   WidthRequest="20"/>
                            <Label Grid.Row ="2"
                                   Grid.Column="1"
                                   Text="{Binding Phone}"
                                   HorizontalOptions="StartAndExpand"
                                   VerticalOptions="Start"
                                   TextColor="Black"
                                   FontSize="Medium"/>
                        </Grid>
                    </Frame>
                </Expander>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

¡Y eso es todo! Expander se encarga del resto, nosotros solo tenemos que definir un header, un contenido para cuando el control se expanda y decir el tipo de animación que debe utilizar. Como habéis podido comprobar este nuevo control tiene un potencial increíble y es super sencillo de utilizar, al final del articulo dejaré un repositorio en GitHub con el ejemplo completo para quien quiera echarle un ojo.

Ver ejemplo completo en GitHub 

Comentarios

Entradas populares de este blog

[Xamarin.Forms] Pasar objetos entre paginas utilizando la navegación de Shell