Qual é a diferença entre as Opções de layout do Xamarin.Form, especialmente Fill e Expand?

170

No Xamarin.Forms, cada um Viewtem as duas propriedades HorizontalOptionse VerticalOptions. Ambos são do tipo LayoutOptionse podem ter um dos seguintes valores:

  • LayoutOptions.Start
  • LayoutOptions.Center
  • LayoutOptions.End
  • LayoutOptions.Fill
  • LayoutOptions.StartAndExpand
  • LayoutOptions.CenterAndExpand
  • LayoutOptions.EndAndExpand
  • LayoutOptions.FillAndExpand

Aparentemente, ele controla o alinhamento da vista na vista pai. Mas como exatamente é o comportamento de cada opção individual? E qual é a diferença entre Fille o sufixo Expand?

Falko
fonte

Respostas:

335

Resposta curta

Start, Center, EndE Filldefinir a vista de alinhamento dentro do seu espaço .

Expanddefine se ele ocupa mais espaço, se disponível.

Teoria

A estrutura LayoutOptionscontrola dois comportamentos distintos:

  1. Alinhamento: como a exibição é alinhada na exibição principal?

    • Start: Para alinhamento vertical, a vista é movida para o topo. Para o alinhamento horizontal, esse geralmente é o lado esquerdo. (Mas observe que em dispositivos com o idioma da direita para a esquerda é o contrário, isto é, alinhado à direita).
    • Center: A vista é centralizada.
    • End: Geralmente a vista está alinhada por baixo ou para a direita. (Nos idiomas da direita para a esquerda, é claro, alinhados à esquerda.)
    • Fill: Esse alinhamento é um pouco diferente. A exibição se estenderá por todo o tamanho da exibição principal.

    Se o pai, porém, não for maior que o filho, você não notará nenhuma diferença entre esses alinhamentos. O alinhamento é importante apenas para as visualizações pai com espaço adicional disponível.

  2. Expansão: o elemento ocupará mais espaço, se disponível?

    • Sufixo Expand: se a visualização pai for maior que o tamanho combinado de todos os seus filhos, ou seja, espaço adicional estiver disponível, o espaço será proporcional entre as visualizações filhos com esse sufixo. Essas crianças "ocuparão" seu espaço, mas não necessariamente o "preencherão". Vamos dar uma olhada nesse comportamento no exemplo abaixo.
    • Sem sufixo: os filhos sem Expandsufixo não receberão espaço adicional, mesmo que haja mais espaço disponível.

    Novamente, se a visualização pai não for maior que seus filhos, o sufixo de expansão também não fará diferença.

Exemplo

Vamos dar uma olhada no exemplo a seguir para ver a diferença entre as oito opções de layout.

O aplicativo contém um cinza escuro StackLayoutcom oito botões brancos aninhados, cada um deles marcado com sua opção de layout vertical. Ao clicar em um dos botões, ele atribui sua opção de layout vertical ao layout da pilha. Dessa forma, podemos testar facilmente a interação das visualizações com os pais, ambos com diferentes opções de layout.

(As últimas linhas de código adicionam caixas amarelas adicionais. Voltaremos a isso daqui a pouco.)

public static class App
{
    static readonly StackLayout stackLayout = new StackLayout {
        BackgroundColor = Color.Gray,
        VerticalOptions = LayoutOptions.Start,
        Spacing = 2,
        Padding = 2,
    };

    public static Page GetMainPage()
    {
        AddButton("Start", LayoutOptions.Start);
        AddButton("Center", LayoutOptions.Center);
        AddButton("End", LayoutOptions.End);
        AddButton("Fill", LayoutOptions.Fill);
        AddButton("StartAndExpand", LayoutOptions.StartAndExpand);
        AddButton("CenterAndExpand", LayoutOptions.CenterAndExpand);
        AddButton("EndAndExpand", LayoutOptions.EndAndExpand);
        AddButton("FillAndExpand", LayoutOptions.FillAndExpand);

        return new NavigationPage(new ContentPage {
            Content = stackLayout,
        });
    }

    static void AddButton(string text, LayoutOptions verticalOptions)
    {
        stackLayout.Children.Add(new Button {
            Text = text,
            BackgroundColor = Color.White,
            VerticalOptions = verticalOptions,
            HeightRequest = 20,
            Command = new Command(() => {
                stackLayout.VerticalOptions = verticalOptions;
                (stackLayout.ParentView as Page).Title = "StackLayout: " + text;
            }),
        });
        stackLayout.Children.Add(new BoxView {
            HeightRequest = 1,
            Color = Color.Yellow,
        });
    }
}

As seguintes capturas de tela mostram o resultado ao clicar em cada um dos oito botões. Nós fazemos as seguintes observações:

  • Enquanto o pai stackLayoutestiver apertado (não Filla página), a opção de layout vertical de cada um Buttonserá insignificante.
  • A opção de layout vertical importa apenas se stackLayoutfor maior (por exemplo, através do Fillalinhamento) e se os botões individuais tiverem o Expandsufixo.
  • Espaço adicional é proporcionalmente proporcional entre todos os botões com Expandsufixo. Para ver isso mais claramente, adicionamos linhas horizontais amarelas entre cada dois botões vizinhos.
  • Os botões com mais espaço do que a altura solicitada não o "preenchem" necessariamente. Nesse caso, o comportamento real é controlado por seu alinhamento. Por exemplo, eles estão alinhados na parte superior, central ou no botão de seu espaço ou preenchem-no completamente.
  • Todos os botões se estendem por toda a largura do layout, pois apenas modificamos o VerticalOptions.

Screenshots

Aqui você encontra as capturas de tela de alta resolução correspondentes.

Falko
fonte
6
imagem parece [[meia]], lol. Apenas caçoando foi realmente útil
Joy Rex
1
@JoyRex: Bem, talvez esta versão seja um pouco menos confusa. ;)
Falko
2
Eu confundi com a saída acima. start e startAndExpand são a mesma saída. Qual é a diferença entre eles? você pode dar uma explicação, se possível ..
Ranjith Kumar
1
FillAndExpandé o que você quer, 99% fo time
Stephane Delcroix
1
@RanjithKumar Eles são os mesmos. Ele StackLayout foi aninhado em outro pais, em seguida, sua FillAndExpand poderia fazer a diferença - que iria expandir dentro de seu pai.
Miha Markic 31/08/19
16

Existe um bug na versão atual do Xamarin.Forms; talvez já esteja lá há um tempo.

CenterAndExpand geralmente não se expande, e contornar isso pode ser confuso.

Por exemplo, se você tiver um StackLayoutconjunto para CenterAndExpand, coloque um rótulo dentro desse conjunto, que também CenterAndExpandseria esperado como um rótulo com a largura total do StackLayout. Não. Não vai se expandir. Você precisa definir StackLayout" FillAndExpand" para fazer com que o objeto Label aninhado se expanda até a largura total do e StackLayout, em seguida, peça ao Label para centralizar o texto, não ele próprio como um objeto HorizontalTextAlignment="Center". Na minha experiência, você precisa que o pai e o filho aninhado sejam configurados para, FillAndExpandse realmente quiser ter certeza de que ele se expande para se encaixar.

        <StackLayout HorizontalOptions="FillAndExpand"
                     Orientation="Vertical"
                     WidthRequest="300">
            <Label BackgroundColor="{StaticResource TileAlerts}"
                   HorizontalOptions="FillAndExpand"
                   Style="{StaticResource LabelStyleReversedLrg}"
                   HorizontalTextAlignment="Center"
                   Text="Alerts" />
Clint StLaurent
fonte
3
"... você esperaria um rótulo com largura total do StackLayout." Esta suposição está incorreta. Expandé usado apenas para filhos de StackLayout. Portanto, se o seu StackLayout for a raiz, ou não em outro StackLayout, Expandnão terá efeito. Em vez disso, qualquer opção diferente de Preenchimento atuaria como um "conteúdo de quebra automática" para dimensionamento, que é o que você vê.
Therealjohn
Além disso, a expansão funciona apenas para LayoutOptions que têm a mesma orientação do StackLayout. Nesse caso, o layout é "Vertical", mas as opções em questão são horizontais (opostas).
Therealjohn
O termo "AndExpand" é ambíguo. Pode ser interpretado como "expanda o máximo possível" ou "expanda apenas o necessário". Acho que a Microsoft deve alterar os termos para algo menos confuso, como "CenterAndExpandToParent" ou "CenterAndExpandAsNeeded"
technoman23
1

Falko deu uma boa explicação, mas eu queria acrescentar isso com outro visual e como essas tags funcionam no xaml, que é o que eu prefiro usar na maioria das vezes. Eu fiz um projeto simples para testar os resultados da exibição. Aqui está o Xaml para a página principal:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Alignments.MainPage"
             BackgroundColor="White">


    <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="LightGray" Padding="1" Margin="30">
        <Label Text="Vert: EndAndExpand, Horz: EndAndExpand" VerticalOptions="EndAndExpand" HorizontalOptions="EndAndExpand" BackgroundColor="White"/>
    </StackLayout>


</ContentPage>

Como você pode ver, é um StackLayout muito simples com uma etiqueta dentro. Para cada imagem abaixo, mantive o StackLayout igual, apenas alterei as opções horizontal e vertical da Entrada e alterei o texto para mostrar as opções selecionadas, para que você possa ver como a Entrada se move e redimensiona.

Start vs StartAndExpand Aqui está o código usado para Iniciar:

<Label Text="Vert: Start, Horz: Start" VerticalOptions="Start" HorizontalOptions="Start" BackgroundColor="White"/>

E o código usado para StartAndExpand:

<Label Text="Vert: StartAndExpand, Horz: StartAndExpand" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand" BackgroundColor="White"/>

Como você pode ver, não há diferença visualmente além de mais texto usado na opção StartAndExpand. Isso foi testado no meu dispositivo físico Samsung A30. Eles podem ser exibidos de maneira diferente em dispositivos diferentes, mas acho que todas as imagens aqui mostram coletivamente que existem alguns erros no Xamarin. Quanto ao resto, mostrarei apenas as capturas de tela, acho que são auto-explicativas.

End vs EndAndExpand

Center vs CenterAndExpand

Fill vs FillAndExpand

Também recomendo dar uma olhada na documentação da Microsoft para obter mais detalhes. Notável é que "a expansão é usada apenas por um StackLayout".

technoman23
fonte
Boa visualização. Mas não vejo por que isso deve mostrar bugs no Xamarin. O que pode ser confuso é que os rótulos podem ocupar mais espaço do que o fundo branco (as regiões cinzas no meu exemplo). Portanto, um rótulo "Vert Center" é centralizado no espaço que ocupa - não na página inteira. Aparentemente, após quase seis anos, esse tópico ainda é tão confuso quanto antes.
Falko