dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.14k stars 1.74k forks source link

Enhance StackLayout and VerticalStackLayout #10224

Open david-maw opened 2 years ago

david-maw commented 2 years ago

Description

Coming from Xamarin I'm used to being able to vertically stack controls in a StackPanel to make up a page. Unfortunately, this no longer works if one of those controls is a CollectionView or an expanding Editor, they misbehave in a variety of ways, expanding past the end of the screen and refusing to scroll.

The workaround for this is to use a Grid instead, defining the row heights with RowDefinitions - this works well enough (bugs aside) but for the developer who is looking for a stacked vertical list of controls it's tedious to enter all the "Grid.Row" values and really tedious when you want to inset an additional one, because subsequent ones must be renumbered and the Grid RowDefinitions updated.

One solution might be to define an item in a grid as falling on the row after the row of the previous item, rather than defaulting to row 0. That removes a lot of the work for the developer but it's a breaking change so maybe requiring Grid.Row="Next" or some such would be better. This solves much of the reordering problem but still carries all the overhead of using a grid when something simpler would do.

My preferred alternative might be a StackLayout attached property, something like "StackLayout.RowHeight", to permit the programmer to specify the amount of vertical space a particular control should take, it would accept the same values as a Grid Rowdefinition Height does (auto, , or a number) with the same meaning, default would be "auto" so it would be a non-breaking change (from MAUI, Xamarin already works differently).

Public API Changes

For example, here's an Editor followed by a CollectionView and a bit of chrome using a grid:

    <Grid RowDefinitions="*,auto,2*,auto">
        <Editor Grid.Row="0" BackgroundColor="AliceBlue" HorizontalOptions="Fill" BindingContext="{x:Reference list}" Text="{Binding Path=SelectedItem}"
                FontSize="100" AutoSize="TextChanges"/>
        <BoxView Grid.Row="1" BackgroundColor="Blue" HeightRequest="5"/>
        <CollectionView Grid.Row="2" ItemsSource="{StaticResource StringList}" SelectionMode="Single" x:Name="list">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Label Text="{Binding}" FontSize="100" LineBreakMode="TailTruncation"/>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
        <BoxView Grid.Row="3" BackgroundColor="Red" HeightRequest="5"/>
    </Grid>

What I actually want to specify is something simpler:

    <VerticalStackLayout>
        <Editor VerticalStackLayout.Rowheight="*" BackgroundColor="AliceBlue" HorizontalOptions="Fill" BindingContext="{x:Reference list}" Text="{Binding Path=SelectedItem}"
                FontSize="100" AutoSize="TextChanges"/>
        <BoxView BackgroundColor="Blue" HeightRequest="5"/>
        <CollectionView VerticalStackLayout.Rowheight="2*" ItemsSource="{StaticResource StringList}" SelectionMode="Single" x:Name="list">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Label Text="{Binding}" FontSize="100" LineBreakMode="TailTruncation"/>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
        <BoxView BackgroundColor="Red" HeightRequest="5"/>
    </VerticalStackLayout>
</ContentPage>

Intended Use-Case

Express the UI designer's objective (a vertically stacked list of controls) as simply as possible with the added bonus of simplifying migration from Xamarin.

hartez commented 2 years ago

This isn't something we would add to VerticalStackLayout because it would introduce complexity to the control and impact performance.

And it sounds like you're not really looking for a stack layout (since you specifically don't want the layout to exceed the height of the container); you're looking for a way to subdivide the container into multiple rows in a single column. Which can be done with a Grid (as you've done above). But understandably, you'd like a way to do that which isn't as verbose (and doesn't require as much work to rearrange). That sort of customization is pretty easy to achieve in MAUI - I've got an example that's very similar to what you're asking for.

If there's sufficient interest, we may eventually add some more specific layouts like this to the included-in-the-core-SDK options. But for the moment we're keeping things as simple and customizable as we can.

david-maw commented 2 years ago

I'm focused on StackLayout because it's what I used to use to get the same effect in Xamarin Forms so discovering it didn't work the same way on MAUI was an unpleasant surprise (to a number of people judging by other Issues).

Still, you are correct, the single column layout you built is darn close to what I need. Visually what I want is a vertical stack of controls that fit on a page and if they don't all fit it's a problem because any sort of page scrolling is likely to be tiresome for the end user. I'd think that requiring all the controls to fit on a page is a common UI constraint (though more for native apps than web apps).

Anyway, for my purposes, what you've already done looks like it will meet my needs nicely, thanks, as for general interest, we'll see, this issue might at least act as a place to start.

Thanks for your reply, it was very helpful.

ghost commented 2 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.