Criar uma interface do usuário consistente usando estilos

Concluído

Os recursos são ótimos para evitar valores duplicados e codificados em sua marcação XAML, mas podem ser tediosos de aplicar. Você atribui cada valor de propriedade individualmente, o que pode resultar em XAML confuso e detalhado. Esta unidade mostra como agrupar várias configurações em um estilo, o que pode ajudar a descodificar seu código e torná-lo mais fácil de manter.

Como os recursos podem atrapalhar seu XAML

Um recurso fornece um valor para uma única propriedade. No entanto, o uso de muitos recursos pode levar a XAML detalhado. Suponha que você queira uma aparência personalizada para seus botões. Primeiro, você cria recursos para os valores de que precisa. Em seguida, você aplica cada recurso a todos os seus botões. O código a seguir mostra como a marcação XAML pode procurar dois botões.

<Button
    Text = "OK"
    BackgroundColor = "{StaticResource highlightColor}"
    BorderColor = "{StaticResource borderColor}"
    BorderWidth = "{StaticResource borderWidth}"
    TextColor = "{StaticResource textColor}" />

<Button
    Text = "Cancel"
    BackgroundColor = "{StaticResource highlightColor}"
    BorderColor = "{StaticResource borderColor}"
    BorderWidth = "{StaticResource borderWidth}"
    TextColor = "{StaticResource textColor}" />

Observe como as mesmas cinco propriedades são definidas em cada um dos botões. O uso de recursos elimina a necessidade de valores repetidos e codificados. No entanto, esse tipo de marcação XAML rapidamente fica difícil de ler. Além disso, se você estiver definindo um grande número de propriedades para cada controle, é fácil omitir acidentalmente uma delas, levando a inconsistências na aparência dos controles. A solução é criar um estilo que atribua todas as quatro propriedades de uma só vez.

O que é um setter?

Setters são os principais componentes que você usa para criar estilos .

Um setter é um contêiner para um par propriedade/valor. Você pode pensar em um setter como representando uma declaração de atribuição. Você especifica qual propriedade atribuir e o valor a ser aplicado. Normalmente, você cria objetos Setter em sua marcação XAML. O exemplo a seguir cria um objeto Setter para a propriedade TextColor.

<Setter Property="TextColor" Value="White" />

Você pode usar um recurso para o valor em um setter, conforme mostrado no código a seguir. Essa técnica é ótima quando você deseja usar o mesmo valor em vários setters.

<Setter Property="TextColor" Value="{StaticResource textColor}" />

Nota

O valor da propriedade especificado em um setter deve ser implementado como uma propriedade vinculável. Todas as propriedades em controles no .NET MAUI que terminam com o sufixo Property são propriedades vinculáveis. Se você estiver tentando usar uma propriedade como TextColor em um setter, verifique se há uma propriedade vinculável correspondente chamada TextColorProperty para esse controle. Na prática, quase todas as propriedades que você vai querer usar em seus setters são implementadas dessa forma.

O que é um estilo?

Um estilo é uma coleção de setters direcionados a um tipo específico de controle. O .NET MAUI requer um tipo de destino para que ele possa certificar-se de que as propriedades em seus setters existem nesse tipo.

O código a seguir mostra um estilo que combina os quatro valores do exemplo anterior. Observe que TargetType está definido como Button e todas as propriedades nos setters são membros da classe Button. Você não pode usar esse estilo para um rótulo, porque a classe Label não inclui a propriedade BorderColor ou BorderWidth.

<Style TargetType="Button">
    <Setter Property="BackgroundColor" Value="#2A84D3" />
    <Setter Property="BorderColor" Value="#1C5F9B" />
    <Setter Property="BorderWidth" Value="3" />
    <Setter Property="TextColor" Value="White" />
</Style>

Definir um estilo

Normalmente, você define estilos como recursos dentro de um objeto ResourceDictionary . Um dicionário de recursos facilita o uso do estilo em vários controles na mesma página ou até mesmo em todo o aplicativo. O código a seguir mostra como definir um estilo como um recurso dentro de um dicionário. Observe que o estilo recebe um nome usando a propriedade x:Key . Nomear um estilo permite que você faça referência a ele de dentro de suas páginas XAML.

<ContentPage.Resources>
    <Style x:Key="MyButtonStyle" TargetType="Button">
        ...
    </Style>
</ContentPage.Resources>

Aplicar um estilo

Você anexa um estilo a um controle atribuindo o nome à propriedade Style . A atribuição faz com que cada um dos objetos Setter no estilo seja aplicado ao controle de destino. O código a seguir mostra como aplicar um estilo de botão a dois botões.

<Button Text="OK" Style="{StaticResource MyButtonStyle}" />
<Button Text="Cancel" Style="{StaticResource MyButtonStyle}" />

No exemplo anterior, você usou a extensão de marcação StaticResource para anexar o estilo aos controles. Essa técnica é ótima quando você não precisa que o estilo seja alterado em tempo de execução. Mas e se você quiser implementar algo como temas dinâmicos, onde a interface do usuário precisa mudar? Nesse caso, você pode usar a extensão de marcação DynamicResource para carregar o estilo.

<Button Text="Cancel" Style="{DynamicResource MyButtonStyle}" />

DynamicResource escuta a substituição da propriedade x:Key no dicionário de recursos. Se você escrever um código que carrega um novo estilo no ResourceDictionary com o mesmo valor x:Key , o novo estilo será aplicado automaticamente à sua interface do usuário.

Usar um estilo implícito para vários controles

Suponha que sua interface do usuário tenha 50 botões e você queira aplicar o mesmo estilo a todos eles. Com o que sabemos até agora, você precisaria atribuir à propriedade Style em cada botão manualmente. Não é tão difícil de fazer, mas ainda é tedioso.

Um estilo implícito é um estilo que você adiciona a um dicionário de recursos sem dar-lhe um identificador x:Key . Os estilos implícitos são aplicados automaticamente a todos os controles do objeto TargetType especificado.

O código a seguir mostra o exemplo anterior declarado como um estilo implícito. Este estilo é aplicado a todos os botões da página.

<ContentPage.Resources>
    <Style TargetType="Button">
        <Setter Property="BackgroundColor" Value="Blue" />
        <Setter Property="BorderColor" Value="Navy" />
        ...
    </Style>
</ContentPage.Resources>

Importante

A correspondência de estilos implícitos com controles requer uma correspondência exata com o TargetType especificado. Os controles que herdam do tipo de destino não receberão os estilos. Para afetar os controles herdados, você pode definir o atributo Style.ApplyToDerivedTypes como True ao definir o estilo. Por exemplo, para aplicar um estilo ao tipo Button e fazê-lo afetar qualquer um dos botões que herdam de Button (como um ImageButton, RadioButton ou um tipo personalizado que você criou), você pode usar um estilo como este.

<ContentPage.Resources>
    <Style TargetType="Button"
           ApplyToDerivedTypes="True">
        <Setter Property="BackgroundColor" Value="Black" />
    </Style>
</ContentPage.Resources>

Substituir um estilo

Você pode pensar em um estilo como fornecendo um conjunto de valores padrão para controles. Um estilo existente pode estar perto de suas necessidades, mas conter um ou dois setters que você não quer. Nesse caso, você pode aplicar o estilo e, em seguida, substituir o valor definindo propriedades diretamente. A configuração explícita é aplicada após o estilo, portanto, substituirá o valor do estilo.

Suponha que você queira usar o seguinte estilo para vários botões em sua página.

<Style x:Key="MyButtonStyle" TargetType="Button">
    <Setter Property="BackgroundColor" Value="Blue" />
    <Setter Property="BorderRadius" Value="10" />
    <Setter Property="BorderWidth" Value="3" />
</Style>

Este estilo funciona para todos os seus botões, exceto Cancelar, que precisa de um fundo vermelho. Você pode usar o mesmo estilo para o botão Cancelar, desde que também defina a propriedade BackgroundColor diretamente. O código a seguir mostra como substituir a configuração de cor.

<Button
    Text="Cancel"
    Style="{StaticResource MyButtonStyle}"
    BackgroundColor="Red"
    ... />

Segmentar um tipo de ancestral

Suponha que você queira uma cor de plano de fundo personalizada para seus botões e rótulos. Você pode criar estilos separados para cada tipo ou pode criar um estilo com TargetType definido como VisualElement. Essa técnica funciona porque VisualElement é uma classe base para Button e Label.

O código a seguir mostra um estilo direcionado a uma classe base que está sendo aplicada a dois tipos derivados diferentes.

<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
    <Setter Property="BackgroundColor" Value="#2A84D3" />
</Style>
...
<Button Style="{StaticResource MyVisualElementStyle}" ... />
<Label Style="{StaticResource MyVisualElementStyle}" ... />

Este exemplo identifica o estilo usando x:Key e os controles o aplicam explicitamente. Um estilo implícito não funciona aqui porque TargetType para um estilo implícito deve ser uma correspondência exata com o tipo de controle.

Use BasedOn para herdar de um estilo

Suponha que você queira criar uma aparência coesa para sua interface do usuário. Você decide que todos os controles devem usar uma cor de plano de fundo consistente. É provável que a definição de cor de fundo apareça em mais do que um dos seus estilos. O código a seguir mostra dois estilos com um setter repetido.

<Style x:Key="MyButtonStyle" TargetType="Button">
    <Setter Property="BackgroundColor" Value="Blue" />
    <Setter Property="BorderColor" Value="Navy" />
    <Setter Property="BorderWidth" Value="5" />
</Style>

<Style x:Key="MyEntryStyle" TargetType="Entry">
    <Setter Property="BackgroundColor" Value="Blue" />
    <Setter Property="TextColor" Value="White" />
</Style>

Você pode usar a herança de estilo para fatorar o setter duplicado em um estilo base. Para criar um estilo derivado, defina sua propriedade BasedOn para fazer referência ao estilo base. O novo estilo herda todos os setters de seu estilo base. O estilo derivado também pode adicionar novos setters ou substituir um setter herdado por um que contenha um valor diferente.

O código a seguir mostra os estilos de exemplo anteriores refatorados em uma hierarquia. O setter comum aparece apenas no estilo base, em vez de ser repetido. Observe que você usa a extensão de marcação StaticResource para procurar o estilo base. Você não pode usar DynamicResource nessa situação.

<Style x:Key="MyVisualElementStyle" TargetType="VisualElement">
    <Setter Property="BackgroundColor" Value="Blue" />
</Style>

<Style x:Key="MyButtonStyle" TargetType="Button" BasedOn="{StaticResource MyVisualElementStyle}">
    <Setter Property="BorderColor" Value="Navy" />
    <Setter Property="BorderWidth" Value="5" />
</Style>

<Style x:Key="MyEntryStyle" TargetType="Entry" BasedOn="{StaticResource MyVisualElementStyle}">
    <Setter Property="TextColor" Value="White" />
</Style>

O valor TargetType dos estilos base e derivado deve ser compatível. Para que os estilos sejam compatíveis, eles devem ter a mesma propriedade TargetType ou o TargetType do estilo derivado é um descendente do TargetType do estilo base.

Verificação de conhecimento

1.

Por que você definiria um estilo dentro de um ResourceDictionary?