NET MAUI - Usando ZIndex para tratar a sobreposição de elementos


 Hoje veremos a propriedade ZIndex e mostrando como podemos tratar a sobreposição de elementos.

O NET Multi-platform App UI (.NET MAUI) é um framework multiplataforma para a criação de aplicativos móveis e de desktop nativos com C# e XAML.

O .NET MAUI é de código aberto e é a evolução do Xamarin.Forms, estendido de cenários móveis a desktops, com controles de IU reconstruídos do zero para desempenho e extensibilidade.

Se você já usou o Xamarin.Forms anteriormente para criar aplicações multiplataforma, você notará muitas semelhanças com o .NET MAUI.

Apresentando a propriedade ZIndex

Para o exemplo deste artigo vamos criar um projeto usando o Visual Studio 2022 Preview usando o template  .NET MAUI  App com o nome MauiApp_ZIndex e vamos alterar o código padrão gerado.

Se você estiver trabalhando no .NET MAUI e tiver dois ou mais controles um sobre o outro que precisam ser revelados com base em determinadas condições, este artigo sem dúvida o ajudará a lidar com esse problema.

A ordem em que um elemento aparece no eixo z é representada pela propriedade ZIndex, uma propriedade adicionada no .NET MAUI Preview 12 a todos os elementos herdados da interface IView. Um controle com um valor de ZIndex mais alto será colocado acima dos outros.

Por exemplo, um controle com ZIndex igual a 0 estará na parte inferior e o controle com ZIndex igual a 1 ou superior estará no topo (exibido).

Neste artigo, vamos explorar os comportamentos do ZIndex com renderização padrão e o procedimento para trazer as views .NET MAUI para a frente.

Vamos iniciar mostrando como é a renderização de controles sem usar a propriedade ZIndex.

No código abaixo temos um exemplo que define elementos Label (view) sem usar a propriedade ZIndex:

...
<Grid>
  <Label Text="View 1"  Margin="10,0,0,0" BackgroundColor="Green"
                Style="{StaticResource labelStyle}" />
  <Label Text="View 2" Margin="30,30,0,0" BackgroundColor="Blue"
                Style="{StaticResource labelStyle}"/>
  <Label Text="View 3"  Margin="60,60,0,0" BackgroundColor="Yellow"
                Style="{StaticResource labelStyle}"/>
  <Label Text="View 4"  Margin="90,90,0,0" BackgroundColor="Red"
                Style="{StaticResource labelStyle}"/>
</Grid>
...

O resultado obtido para este código é o seguinte:

Observe que temos uma sobreposição dos elementos que segue a ordem de exibição da view.

Vejamos agora como renderizar esses elementos usando ZIndex.

Para isso vamos redefinir o código acima onde em cada view vamos definir um valor para a propriedade ZIndex. 

 <Grid>
    <Label Text="View 1" ZIndex="4" Margin="10,0,0,0" BackgroundColor="Green"
              Style="{StaticResource labelStyle}" />
    <Label Text="View 2" ZIndex="3" Margin="30,30,0,0" BackgroundColor="Blue"
              Style="{StaticResource labelStyle}"/>
    <Label Text="View 3" ZIndex="2" Margin="60,60,0,0" BackgroundColor="Yellow"
              Style="{StaticResource labelStyle}"/>
    <Label Text="View 4" ZIndex="1" Margin="90,90,0,0" BackgroundColor="Red"
              Style="{StaticResource labelStyle}"/>
 </Grid>

Observe que a última view Label foi definida com o valor ZIndex igual a 1 e a primeira com valor igual a 4. Com isso a primeira view agora estará sendo exibida no topo e a última view estará sendo sobreposta sendo a última view na ordem de exibição.


Vejamos agora como controlar a ordem de exibição trazendo a exibição de uma view para frente.

Para isso vamos criar a classe MainPageViewModel.cs na raiz do projeto com o seguinte código:

namespace MauiApp_ZIndex;

public class MainPageViewModel
{
    private static int Zindex = 10;
    private Command trazerParaFrente;

    public Command TrazerParaFrente
    {
        get { return trazerParaFrente; }
        set { trazerParaFrente = value; }
    }

    public MainPageViewModel()
    {
        trazerParaFrente = new Command<object>(OnTrazerParaFrenteAsync);
    }

    private async void OnTrazerParaFrenteAsync(object view)
    {
        var viewName = (view as Label).Text;
        bool answer = await Application.Current.MainPage.DisplayAlert("Trazer para frente",
                      "Sou a " + viewName + " , " + "Posso mover para frente ?", "Sim", "Não");
        if (answer)
        {
            (view as Label).ZIndex = Zindex;
            Zindex += 1;
        }
    }
}

Nesta view model definimos o comando TrazerParaFrente onde na sua implementação estamos alterando o valor de ZIndex para mover a view para o topo na ordem de exibição.

Agora na page MainPage vamos alterar o código para vincular esta view model com a view MainPage e definir em cada Label a propriedade GestureRecognizers onde estamos vinculando com o comando TrazerParaFrente passando como parâmetro a respectiva View que é recebida e tem o valor do seu ZIndex alterado.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp_ZIndex.MainPage"
             xmlns:local="clr-namespace:MauiApp_ZIndex"
             BackgroundColor="{DynamicResource SecondaryColor}">

    <ContentPage.Resources>
        <Style x:Key="labelStyle" TargetType="{x:Type Label}">
            <Setter Property="WidthRequest" Value="150"/>
            <Setter Property="HeightRequest" Value="150"/>
            <Setter Property="HorizontalOptions" Value="Center"/>
            <Setter Property="VerticalOptions" Value="Center"/>
            <Setter Property="FontSize" Value="Medium"/>
            <Setter Property="FontAttributes" Value="Bold"/>
            <Setter Property="TextColor" Value="White"/>
            <Setter Property="VerticalTextAlignment" Value="Center"/>
            <Setter Property="HorizontalTextAlignment" Value="Center"/>
        </Style>

        <Style x:Key="labelTextStyle" TargetType="{x:Type Label}">
            <Setter Property="HorizontalOptions" Value="Start"/>
            <Setter Property="VerticalOptions" Value="Center"/>
            <Setter Property="FontSize" Value="Title"/>
            <Setter Property="FontAttributes" Value="Bold"/>
            <Setter Property="TextColor" Value="Black"/>
            <Setter Property="VerticalTextAlignment" Value="Center"/>
            <Setter Property="HorizontalTextAlignment" Value="Center"/>
        </Style>
    </ContentPage.Resources>

    <ContentPage.BindingContext>
   
    <local:MainPageViewModel/>
    </ContentPage.BindingContext>

    <StackLayout Orientation="{OnPlatform Default=Horizontal, Android=Vertical, iOS=Vertical}"
                    VerticalOptions="CenterAndExpand"  HorizontalOptions="CenterAndExpand">
        <StackLayout>
            <Grid>
                <Label x:Name="view1" Text="View 1" ZIndex="4" Margin="10,0,0,0" BackgroundColor="Green"
                                                    Style="{StaticResource labelStyle}" >
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding TrazerParaFrente}"
                                                   CommandParameter="{Binding Source={x:Reference view1}}"/>

                    </Label.GestureRecognizers>
                </Label>
                <Label x:Name="view2" Text="View 2" ZIndex="3" Margin="30,30,0,0" BackgroundColor="Navy"
                                                    Style="{StaticResource labelStyle}">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding TrazerParaFrente}"
                                                      CommandParameter="{Binding Source={x:Reference view2}}"/>

                    </Label.GestureRecognizers>
                </Label>
                <Label x:Name="view3" Text="View 3" ZIndex="2" Margin="60,60,0,0" BackgroundColor="Yellow"
                                                             Style="{StaticResource labelStyle}">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding TrazerParaFrente}"
                                                             CommandParameter="{Binding Source={x:Reference view3}}"/>

                    </Label.GestureRecognizers>
                </Label>
                <Label x:Name="view4" Text="View 4" ZIndex="1" Margin="90,90,0,0" BackgroundColor="SkyBlue"
                                                          Style="{StaticResource labelStyle}">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Command="{Binding TrazerParaFrente}"
                                                          CommandParameter="{Binding Source={x:Reference view4}}"/>

                    </Label.GestureRecognizers>
                </Label>
            </Grid>
        </StackLayout>
    </StackLayout>
</ContentPage>

Executando o projeto agora podemos selecionar uma view e alterar a ordem de exibição colocando-a no topo da ordem de exibição:

Aguarde mais novidades e novos artigos sobre o Net. MAUI.

Pegue o projeto aqui:  MauiApp_ZIndex.zip (sem as referências...)

'Sede pois, irmãos, pacientes até à vinda do Senhor. Eis que o lavrador espera o precioso fruto da terra, aguardando-o com paciência, até que receba a chuva temporã e serôdia.'
Tiago 5:7

Referências:


José Carlos Macoratti