Android – Xamarin.Forms – Grid – Afficher plus de colonnes en orientation paysage

Optimiser l’affichage suivant l’orientation de l’écran peut être très intéressant sur des Smartphones voir indispensable.

Dans le cadre du développement de mon application Smartdrive, je souhaitais afficher un tableau de statistiques où

le nombre de colonnes changeait suivant l’orientation de l’écran.

En Portrait, l’affichage ne devait comporter que 3 colonnes alors qu’en paysage nous en voulons 6.

2 solutions possibles :

1 – Utiliser une « Listview »; cela permet de modifier simplement le nombre de colonnes en travaillant uniquement sur le binding. Cette solution est efficace et performante mais ne permet pas d’aligner verticalement les colonnes.

2 – Utiliser un « GridView »; à l’inverse du « Listview » l’alignement vertical est une simple formalité puisqu’il s’agit d’un tableau. Mais il n’est pas possible de modifier le nombre de colonnes grâce au binding. (Risque de crash).

J’ai choisi d’utiliser un « GridView » en jouant avec l’attribut « macolonne.IsVisible » afin de faire apparaître ou disparaître les colonnes.

Mon approche n’utilise pas de XAML.

1. J’utilise une Class dérivée de « Grid » pour générer mon tableau :

 public class CustomGridStatistiques : Grid
    {
        public CustomGridStatistiques(IList stats)
        {
            // Gestion des unités & symbols
            var unitD = new UnitesMesure().Distances().Where(d => d.Id == Helpers.Settings.UnitDistance).Select(p => p.Symbol).FirstOrDefault();
            var unitV = new UnitesMesure().Volumes().Where(d => d.Id == Helpers.Settings.UnitVolume).Select(p => p.Symbol).FirstOrDefault();

            CultureInfo cu = CultureInfo.CurrentCulture;
            NumberFormatInfo nfi = cu.NumberFormat;
            var symbol = nfi.CurrencySymbol;


            // Définition du Grid
            this.VerticalOptions = LayoutOptions.Start;
            this.HorizontalOptions = LayoutOptions.FillAndExpand;

            this.ColumnSpacing = 0;

            this.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); // Vehicule
            this.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); // Total distance 
            this.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); // Total coût carburant
            this.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); // Totalcoût entretien 
            this.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); // Conso Moyenne 
            this.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(100, GridUnitType.Absolute) }); // Coût au km

            foreach (var stat in stats)
            {
                this.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
            }
            var margin = new Thickness { Right = 5 };
            var marginstart = new Thickness { Left = 5 };

            //Définition Headers
            this.Children.Add(new Label
            {
                Text = MobileSmartDrive.Resources.AppResources.label_Vehicule,
                HorizontalTextAlignment = TextAlignment.Start,
                Style = (Style)Application.Current.Resources["headerCol"],
                Margin = marginstart
            }, 0, 0);

            this.Children.Add(new Label
            {
                Text = MobileSmartDrive.Resources.AppResources.tab_header_TotalDistanceTraveled,
                HorizontalTextAlignment = TextAlignment.End,
                Style = (Style)Application.Current.Resources["headerCol"],
                Margin = margin
            }, 1, 0);

            this.Children.Add(new Label
            {
                Text = MobileSmartDrive.Resources.AppResources.tab_header_TotalFuel,
                HorizontalTextAlignment = TextAlignment.End,
                Style = (Style)Application.Current.Resources["headerCol"],
                Margin = margin
            }, 2, 0);

            this.Children.Add(new Label
            {
                Text = MobileSmartDrive.Resources.AppResources.tab_header_TotalRepair,
                HorizontalTextAlignment = TextAlignment.End,
                Style = (Style)Application.Current.Resources["headerCol"],
                Margin = margin
            }, 3, 0);
            this.Children.Add(new Label
            {
                Text = MobileSmartDrive.Resources.AppResources.tab_header_AverageConsumption,
                HorizontalTextAlignment = TextAlignment.End,
                Style = (Style)Application.Current.Resources["headerCol"],
                Margin = margin
            }, 4, 0);

            this.Children.Add(new Label
            {
                Text = string.Format(MobileSmartDrive.Resources.AppResources.tab_header_CostByUnit, unitD),
                HorizontalTextAlignment = TextAlignment.End,
                Style = (Style)Application.Current.Resources["headerCol"],
                Margin = margin
            }, 5, 0);


            // Ajout du contenu 
            try
            {

                // On utilise un compteur pour alterner la couleur des lignes (pyjama)
                int i = 1;
                foreach (var stat in stats)
                {
                    var labelVehicule = new Label
                    {
                        Text = stat.Vehicule,
                        HorizontalTextAlignment = TextAlignment.Start,
                        Style = (Style)Application.Current.Resources["header"] 
                    };

                    var labelDistanceParcouru = new Label
                    {
                        Text = string.Format(MobileSmartDrive.Resources.AppResources.format_Distance, stat.TotalKmParcouru, unitD),
                        HorizontalTextAlignment = TextAlignment.End 
                    };

                    var labelFuelCost = new Label
                    {
                        Text = string.Format(MobileSmartDrive.Resources.AppResources.format_SimpleCost, Math.Round(stat.CoutTotalCarburant, 2), symbol),
                        HorizontalTextAlignment = TextAlignment.End 
                    };

                    var labelCostRepair = new Label
                    {
                        Text = string.Format(MobileSmartDrive.Resources.AppResources.format_SimpleCost, stat.CoutTotalEntretien, symbol),
                        HorizontalTextAlignment = TextAlignment.End 
                    };

                    var labelAverageConso = new Label
                    {
                        Text = string.Format(MobileSmartDrive.Resources.AppResources.format_AverageConsumption, Math.Round(stat.ConsoMoyenne, 2), unitV, unitD),
                        HorizontalTextAlignment = TextAlignment.End 
                    };

                    var labelCostByUnit = new Label
                    {
                        Text = string.Format(MobileSmartDrive.Resources.AppResources.format_CostByDistance, Math.Round(stat.CoutAuKilometre, 2), symbol, unitD),
                        HorizontalTextAlignment = TextAlignment.End,
                        Style = (Style)Application.Current.Resources["importanteData"]
                    };

                    // Pyjama 
                    if (i % 2 == 1 && stats.Count > 1)
                    {
                        labelVehicule.BackgroundColor = (Color)Application.Current.Resources["alternateRowColor1"];
                        labelDistanceParcouru.BackgroundColor = (Color)Application.Current.Resources["alternateRowColor1"];
                        labelFuelCost.BackgroundColor = (Color)Application.Current.Resources["alternateRowColor1"];
                        labelCostRepair.BackgroundColor = (Color)Application.Current.Resources["alternateRowColor1"];
                        labelAverageConso.BackgroundColor = (Color)Application.Current.Resources["alternateRowColor1"];
                        labelCostByUnit.BackgroundColor = (Color)Application.Current.Resources["alternateRowColor1"];
                    }

                    // Ajout des labels au Grid
                    this.Children.Add(labelVehicule, 0, i);
                    this.Children.Add(labelDistanceParcouru, 1, i);
                    this.Children.Add(labelFuelCost, 2, i);
                    this.Children.Add(labelCostRepair, 3, i);
                    this.Children.Add(labelAverageConso, 4, i);
                    this.Children.Add(labelCostByUnit, 5, i);
                    i++;
                }

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }

2. J’instancie le Grid dans le constructeur de ma Class Page (ContentPage)

      
Grid gridStat;
public StatistiquesPage()
{
     gridStat = new CustomGridStatistiques(new List());            
     this.Content = gridStat;
}

La page est prête avec un affichage complet de toutes les colonnes quelle que soit l’orientation.

Let’s do some magic
La gestion de l’orientation se fait dans la méthode « OnSizeAllocated » de la classe « ContentPage ».
Dans notre cas, nous souhaitons jouer avec les colonnes de 1 à 3. Pour cela nous allons :

  1. Itérer sur tous les enfants de la Grid
  2. Récupérer la propriété « Grid.ColumnProperty »
  3. Modifier l’attribut « IsVisible » Pour les colonnes de 1 à 3
 
protected override void OnSizeAllocated(double width, double height)
{
        base.OnSizeAllocated(width, height);           

        // On parcourt les éléments du GRID
        foreach (View child in gridStat.Children)
        {
            // On utilise ColumnProperty pour agir uniquement sur les colonnes voulues
            if ((int)child.GetValue(Grid.ColumnProperty) > 0 && (int)child.GetValue(Grid.ColumnProperty) <= 3) { // Si la largeur est supérieur à la hauteur, nous sommes en Paysage // Dans ce cas on affiche toutes les colonnes child.IsVisible = (width > height);
            }
      }
}

Le tour est joué, le nombre de colonnes change suivant l’orientation tout en étant parfaitement aligné verticalement.


Statistiques Portrait Xamarin Grid
3 Colonnes affichées en orientation portrait

Statistiques Paysage Xamarin Grid
6 Colonnes affichées en orientation paysage

Si vous avez trouvé ce tuto utile, n’hésitez pas à le commenter et à partager. Bon code !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *