.NET Maui динамически изменяет макет в зависимости от отображаемых регионов

У меня есть страница, содержащая три области (каждая VerticalStackLayout с Label и Frame с CollectionView) с двумя Buttons внизу. Каждая из областей может отображаться или не отображаться в зависимости от базовых условий. Какая бы из областей ни была видимой (три, две или одна — и это могут быть любые две или любая одна), она должна расширяться, чтобы заполнить доступное пространство просмотра. Но мне не удалось найти правильную комбинацию элементов XAML, чтобы это произошло.

В настоящее время у меня есть эта структура:

<Grid
    ColumnDefinitions = "*,*"
    RowDefinitions = "*,60">
    <VerticalStackLayout Grid.Row = "0" Grid.ColumSpan = "2">
        <VerticalStackLayout IsVisible = "{Binding ConditionA}">
            <Label Text = "States" />
            <Frame HeightRequest = "150">
                <CollectionView />
            </Frame>
        </VerticalStackLayout>
        <VerticalStackLayout IsVisible = "{Binding ConditionB}">
            <Label Test = "Topics" />
            <Frame HeightRequest = "150">
                <CollectionView />
            </Frame>
        </VerticalStackLayout>
        <VerticalStackLayout IsVisible = "{Binding ConditionC}">
            <Label Text = "Activities" />
            <Frame HeightRequest = "150">
                <CollectionView />
            </Frame>
        </VerticalStackLayout>
    </VerticalStackLayout>
    <Button Grid.Row = "1" Grid.Column = "0" />
    <Button Grid.Row = "1" Grid.Column = "1" />
</Grid>

Без HeightRequest на FrameCollectionView расширяется, чтобы заполнить всю страницу и ниже, убегая от нижней части страницы. Идея программного управления HeightRequest (т. е. вычисления соответствующей высоты для отображаемых областей) просто не кажется правильной. Похоже, что расширение должно обрабатываться элементами XAML в зависимости от доступного пространства; например, HorizontalOptions = "CenterAndExpand" или что-то в этом роде.

Таким образом, когда все три области видны, они должны отображать вечер по всей странице сверху вниз:

           List A
+-----------------------------+
|                             |
|                             |
|                             |
|                             |
|                             |
|                             |
+-----------------------------+

           List B
+-----------------------------+
|                             |
|                             |
|                             |
|                             |
|                             |
|                             |
+-----------------------------+

           List C
+-----------------------------+
|                             |
|                             |
|                             |
|                             |
|                             |
|                             |
+-----------------------------+

   +----------+ +-----------+
   |  Button  | |  Button   |
   +----------+ +-----------+

Но если только две области, высота областей должна быть увеличена, чтобы сбалансировать пространство просмотра:

           List A
+------------------------------+
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
+------------------------------+

           List C
+------------------------------+
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
+------------------------------+

   +----------+ +-----------+
   |  Button  | |  Button   |
   +----------+ +-----------+

Или, если отображается только один регион, он должен заполнять доступное пространство просмотра:

           List B
+------------------------------+
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
|                              |
+------------------------------+

   +----------+ +-----------+
   |  Button  | |  Button   |
   +----------+ +-----------+

ОБНОВЛЕНИЕ: вот что я сделал, основываясь на ответе.

XAML

<Grid
    ColumnDefinitions = "*,*">
    <Grid.RowDefinitions>
        <RowDefinition x:Name = "MainArea" Height = "*" />
        <RowDefinition x:Name = "ButtonArea" Height = "60" />
    </Grid.RowDefinitions>
    <VerticalStackLayout Grid.Row = "0" Grid.ColumSpan = "2">
        <VerticalStackLayout x:Name = "StatesFilter" IsVisible = "{Binding ConditionA}">
            <Label Text = "List A" />
            <Frame x:Name = "StatesFrame" HeightRequest = "150">
                <CollectionView />
            </Frame>
        </VerticalStackLayout>
        <VerticalStackLayout x:Name = "TopicsFilter" IsVisible = "{Binding ConditionB}">
            <Label Test = "List B" />
            <Frame x:Name = "TopicsFrame" HeightRequest = "150">
                <CollectionView />
            </Frame>
        </VerticalStackLayout>
        <VerticalStackLayout x:Name = "ActivitiesFilter" IsVisible = "{Binding ConditionC}">
            <Label Text = "List C" />
            <Frame x:Name = "ActivitiesFrame" HeightRequest = "150">
                <CollectionView />
            </Frame>
        </VerticalStackLayout>
    </VerticalStackLayout>
    <Button Grid.Row = "1" Grid.Column = "0" />
    <Button Grid.Row = "1" Grid.Column = "1" />
</Grid>

Код программной части

protected override void OnSizeAllocated(double width, double height)
{
    base.OnSizeAllocated(width, height);

    // This is called twice, once with -1, -1 then the next call with
    // the actual width and height.
    if (Height > 0)
    {
        AdjustRegionHeight(height);
    }
}

private void AdjustRegionHeight(double pageHeight)
{
    double frameHeight;
    double bottomSpace = 44; 

    int cnt = 0;
    cnt += (StatesFilter.IsVisible) ? 1 : 0;
    cnt += (TopicsFilter.IsVisible) ? 1 : 0;
    cnt += (ActivitiesFilter.IsVisible) ? 1 : 0;

    double fullHeight = pageHeight - ButtonArea.Height.Value;
    frameHeight = (fullHeight / cnt) - bottomSpace;

    StatesFrame.HeightRequest = (StatesFilter.IsVisible) ? frameHeight : 0;
    TopicsFrame.HeightRequest = (TopicsFilter.IsVisible) ? frameHeight : 0;
    ActivitiesFrame.HeightRequest = (ActivitiesFilter.IsVisible) ? frameHeight : 0;
}

В VerticalStackLayout нет механизма, который мог бы решить эту проблему. Вместо этого сделайте их 3-мя рядами сетки. В коде позади установите RowDefinitions в зависимости от того, какие из них видны. * за каждый видимый, 0 за каждый скрытый. myGridName.RowDefinitions = new RowDefinitions ... Если вы застряли, пытаясь понять, как это сделать, продвиньтесь как можно дальше и добавьте свой код к вопросу.

ToolmakerSteve 03.02.2023 00:36
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Идея программного управления HeightRequest (т. е. вычисления соответствующей высоты для отображаемых областей) просто не кажется правильной. Похоже, что расширение должно обрабатываться элементами XAML в зависимости от доступного пространства;

Наоборот, идея программного управления HeightRequest, скорее всего, будет реализована.

Судя по вашему коду, я не знаю кода {Binding ConditionA}. Итак, чтобы реализовать это требование: нажмите кнопку, чтобы изменить макет:

.xaml:

<ContentPage xmlns = "http://schemas.microsoft.com/dotnet/2021/maui" 
             xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class = "MauiApp1.NewPage1" 
             Title = "NewPage1">
  <Grid ColumnDefinitions = "*,*" RowDefinitions = "*,60">
       <VerticalStackLayout Grid.Row = "0" Grid.ColumnSpan = "2">
              <VerticalStackLayout x:Name = "ListA" IsVisible = "true">
                     <Label Text = "List A" />
                     <Frame x:Name = "FrameA" HeightRequest = "150">
                            <CollectionView />
                     </Frame>
              </VerticalStackLayout>
              <VerticalStackLayout x:Name = "ListB" IsVisible = "true">
                     <Label Text = "List B" />
                     <Frame x:Name = "FrameB" HeightRequest = "150">
                            <CollectionView />
                     </Frame>
              </VerticalStackLayout>
              <VerticalStackLayout x:Name = "ListC" IsVisible = "true">
                     <Label Text = "List C" />
                     <Frame x:Name = "FrameC" HeightRequest = "150">
                            <CollectionView />
                     </Frame>
              </VerticalStackLayout>
       </VerticalStackLayout>
       <Button Grid.Row = "1" Grid.Column = "0" Clicked = "onlyOne"/>
       <Button Grid.Row = "1" Grid.Column = "1" Clicked = "Two"/>
  </Grid>
</ContentPage>

.xaml.cs:

public partial class NewPage1 : ContentPage
{
    public NewPage1()
    {
        InitializeComponent();
    }

    private void onlyOne(object sender, EventArgs e)
    {
        //change the state of IsVisible of VerticalStackLayout        
        ListB.IsVisible = false;
        ListA.IsVisible = false;
        ListC.IsVisible = true;

        FrameC.HeightRequest = 450;
    }

    private void Two(object sender, EventArgs e)
    {
        ListC.IsVisible = false;
        ListB.IsVisible = true;
        ListA.IsVisible = true;
        
        FrameA.HeightRequest = 225;
        FrameB.HeightRequest = 225;
    }
}

Первая кнопка предназначена для отображения только одного региона (список C). Вторая кнопка заключается в том, что отображаются только две области (список A и B).

Возвращаясь к вашей ситуации, ConditionA/B/C change эквивалентно нажатию кнопки выше. Вы можете добавить логику кода в Button.Clicked к функции ConditionA/B/C change.

Собственно, я так и сделал в свое время. Тем не менее, это казалось неправильным, потому что теперь код должен знать об устройстве, на котором он работает, поскольку размер устройства может отличаться. Это заставило меня рассмотреть другие варианты. Но, безусловно, код программной части — это правильное место, где можно узнать о доступном пространстве.

AdvApp 03.02.2023 20:36

Другие вопросы по теме