Search code examples
androidxamarin.androidxamarin.formsxamarin.forms-styles

Xamarin.Forms (XAML): scaling to smaller screens


I have been developing an application using Xamarin Forms and am having problems with smaller screen sizes (480x640 and 480x800 for example). Basically, the content of the form is being clipped...

An image of the form on the smaller screen

Note the buttons at the bottom have been clipped.

Within the XAML I am not specifying any sizes so I expect the forms to adapt to the available size...

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MyCompany.Views.MyPage" x:Name="MyPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:MyCompany.Views" Padding="15" Title="{Binding Path=Title}">

    <StackLayout>

        <StackLayout VerticalOptions="Start">
            <Label HorizontalTextAlignment="Center" Text="Type barcode manually if required" />
            <Entry Text="{Binding Path=BarcodeContent}" />
            <Button Command="{Binding Path=OkCommand}" HorizontalOptions="Center" Text="Ok" />
        </StackLayout>

        <ListView ItemsSource="{Binding Path=History}" VerticalOptions="Fill">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextCell Text="{Binding Path=BarcodeContent}">
                        <TextCell.ContextActions>
                            <MenuItem Command="{Binding Path=BindingContext.EnquiryCommand, Source={x:Reference MyPage}}" CommandParameter="{Binding}" Text="Enquiry" />
                            <MenuItem Command="{Binding Path=BindingContext.RaiseCommand, Source={x:Reference MyPage}}" CommandParameter="{Binding}" Text="Raise" />
                        </TextCell.ContextActions>
                    </TextCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

        <Grid VerticalOptions="End">

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="2*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="2*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Button Grid.Column="1" Command="{Binding Path=CancelCommand}" Text="Cancel" />
            <Button Grid.Column="3" Command="{Binding Path=ContinueCommand}" Text="Complete" />

        </Grid>

    </StackLayout>

</ContentPage>

When displayed on a 1080 x 1920 pixel display, all is well.

What am I missing here?

EDIT:

If I replace the outer StackView with a Grid, everything fits...

<Grid>

    <Grid.RowDefinitions>
        <RowDefinition Height="auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>

    <StackLayout Grid.Row="0">
    </StackLayout>

    <ListView Grid.Row="1" ...>
    </ListView>

    <Grid Grid.Row="2">
    </Grid>

</Grid>

So, I have a work around but still do not understand why the original StackView version does not work (is there a preferred default height to the ListView control for example?).


Solution

  • While I would have to delve down in to the code to find the exact reason, the most likely suspect is the ListView. The StackLayout doesn't just fit the screen, it expands to contain everything that is inside of it.

    The ListView, most likely is bigger than anticipated, due to the VerticalOptions="Fill" and hence is taking all that space you are seeing. If you change the background color on your ListView, you will see what area it is taking. But you can change the background color on all containers on the screen, and its normally the best way to see whats taking space.

    A Grid on the other hand, will just fill the exact space on the screen, and its rows are split with what space is available inside.

    To summarize, a StackLayout expands beyond the screen to fit what is contained inside it. A Grid will fill out to the size of its parent, e.g. the screen, by default, then you split the space inside of it.