I have a form with a vertical stack layout. It has two children. The first (topmost) child is an Entry. The second child is a list view. My issue is I want the listview to expand to fill the remaining space on the screen and then be scrollable. Short of setting a specific height for the list view (which will obviously not work on different screen sizes) I have been unable to achieve this. If I set the list view's vertical option to be FillAndExpand it seems to expand off the edge of the screen and you can't scroll to the bottom most entries in the list view. How can I achieve this without setting a specific height? This layout is generated dynamically in C# btw. The parent stack layout's vertical option is FillAndExpand too.
I have tried using a grid as per @KFactory suggestion. When I did that I got this result:
You can see there is a gap at the bottom that the list view has not filled.
This is the Page the views are being added to:
<?xml version="1.0" encoding="utf-8" ?>
<local:BaseContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TecMan.MobileApp"
xmlns:f="clr-
namespace:TecMan.MobileApp.Behaviours;assembly=TecMan.MobileApp"
x:Class="TecMan.MobileApp.MainPage">
<AbsoluteLayout x:Name="frmLayout" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="LightGray">
<StackLayout
Orientation="Vertical"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Grid
x:Name="frmMain"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
RowSpacing="0">
<local:BaseContentPage.Behaviors>
<f:BindingChangedBehaviour/>
</local:BaseContentPage.Behaviors>
</Grid>
</StackLayout>
</AbsoluteLayout>
</local:BaseContentPage>
The controls are being added to the grid 'frmMain'
In the code behind the controls are being added dynamically (the content varies depending on the scenario). The rows / columns and grid locations of the controls are defined thus:
Grid frmMain = page as Grid; //page.FindByName<Grid>("frmMain");
if (frmMain == null) throw new NotImplementedException("Only support Grid");
frmMain.ColumnDefinitions.Clear();
frmMain.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
});
frmMain.RowDefinitions.Clear();
frmMain.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Auto)
});
frmMain.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
Grid.SetColumn(btnFrame, 0);
Grid.SetRow(btnFrame, 0);
Grid.SetColumn(oViewColumn, 0);
Grid.SetRow(oViewColumn, 1);
The first control is an entry wrapped in a frame. The second control is a custom listview whose xaml is:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TecMan.MobileViewModels.Controls.CollapsibleListView"
xmlns:local="clr-namespace:TecMan.MobileViewModels.Controls;assembly=TecMan.MobileViewModels" >
<ContentView.Content
BackgroundColor="LightGrey" >
<ListView
VerticalOptions="FillAndExpand"
BackgroundColor="White"
HasUnevenRows="True"
RowHeight="-1"
x:Name="collapseLV"
MinimumHeightRequest="1000"
ItemsSource="{Binding Items}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<local:CollapsibleGridView Title="{Binding Title}"
TitleColour="#99ff66"
ButtonVisible="{Binding ButtonVisible}"
CaptionField="{Binding CaptionField}"
DataField="{Binding DataField}"
IsHiddenField="{Binding IsHiddenField}"
ButtonColour="{Binding ButtonColour}"
VisibleItemsColour="{Binding VisibleItemsColour}"
HiddenItemsColour="{Binding HiddenItemsColour}"
CellBackgroundColor="{Binding CellBackgroundColor}"
ImageFile="{Binding ImageFile}"
ItemsSource="{Binding}">
</local:CollapsibleGridView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentView.Content>
</ContentView>
Xamarin Forms is not (yet) powerfull as WPF... There are some 'unnatural' behaviors. In my case I use to use Grid Controls like this:
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Row 0: your entry />
<Entry Grid.Row="0" ... />
<!-- Row 1: your Listview that will take all available remaining space />
<Listview Grid.Row="1"
...
/>
</Grid>
Note the 'RowSpacing' property of the Grid is set to '0' to avoid empty space between your controls. Should be working now...
Edit 1 (Full xaml code):
<?xml version="1.0" encoding="utf-8" ?>
<local:BaseContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TecMan.MobileApp"
xmlns:f="clr-
namespace:TecMan.MobileApp.Behaviours;assembly=TecMan.MobileApp"
x:Class="TecMan.MobileApp.MainPage">
<!-- Set your page's behavior here -->
<local:BaseContentPage.Behaviors>
<f:BindingChangedBehaviour/>
</local:BaseContentPage.Behaviors>
<!-- Set directly a grid as content of your page -->
<Grid
x:Name="frmMain"
BackgroundColor="LightGray"
RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition x:Name="r1" Height="Auto" />
<RowDefinition x:Name="r2" Height="*" />
</Grid.RowDefinitions>
<!-- Row 0: your entry />
<Entry Grid.Row="0" ... />
<!-- Row 1: your Listview that will take all available remaining space />
<local:CollapsibleListView
Grid.Row="1"
...
/>
</Grid>
</local:BaseContentPage>
In the code behind use rows names ('r1' & 'r2') to add your controls.
BUT I suggest you to not mix XAML and code behind UI initialization... It's not really clear and source of mistakes...