ListView padding before and after items - xamarin

My ListViews all add a huge amount of padding before and after their children.
For example I have the following ListView in my master
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModel="clr-namespace:ViewModel;assembly=App"
x:Class="Pages.Master"
Title="Menu">
<ContentPage.BindingContext>
<viewModel:MasterViewModel />
</ContentPage.BindingContext>
<ListView ItemsSource="{Binding Pages}"
ItemSelected="ListView_OnItemSelected"
BackgroundColor="Red">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="S" BackgroundColor="White" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
And it renders the following:
And as soon as you scroll just a little it'll reveal the first element (i.e. the top red space is equal to the height)
Similarly you can keep scrolling until the last item completely disappears (i.e. the bottom red space is equal to the height)
I don't change the properties/styling of ANY of the views in code - it's all done in the XAML, so why is there such a huge amount of space before and after?

It appears to be a problem with the rendering of ListView.Header and ListView.Footer
I added the following to my list view XAML and it removed the giant padding:
<ListView.Header>
<StackLayout HeightRequest="0" />
</ListView.Header>
<!-- ItemTemplate -->
<ListView.Footer>
<StackLayout HeightRequest="0" />
</ListView.Footer>
As this problem was affecting all of my list views, I chose to instead add it as a globally applied style in my App.xaml:
<Style TargetType="ListView">
<Setter Property="Header">
<Setter.Value>
<StackLayout HeightRequest="0" />
</Setter.Value>
</Setter>
<Setter Property="Footer">
<Setter.Value>
<StackLayout HeightRequest="0" />
</Setter.Value>
</Setter>
</Style>

Related

Xamarin: How to Add a Background Image to All Pages with an AspectFill property

Total newbie Xamarin user.
I'm trying to add a background image to all the pages in the mobile app.
This was a great resource: Xamarin.Forms How to add Backgroud Image on all pages in App
However, I'd like to adjust the Aspect property of the image to AspectFill, so it's not so scrunched up. This is where I'm having trouble.
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.App">
...
<Application.Resources>
<ResourceDictionary>
<Style TargetType="ContentPage" ApplyToDerivedTypes="True" >
<Setter Property="BackgroundImageSource" Value="background_image.png" />
</Style>
...
This sets the background image. How do I adjust the Aspect property for all pages? I've tried nesting an <Image Aspect="AspectFill" /> tag within the Setter property tag, but VS gives a warning that the "property 'Value' is set more than once". Could someone help me out? I'm sure I'm making some dumb error or I've misunderstood something about Xamarin.
Thanks.
Yes, we can use the following method to set the BackgroundImageSource for all ContentPage in your app:
<Application.Resources>
<ResourceDictionary>
<Style TargetType="ContentPage" ApplyToDerivedTypes="True" >
<Setter Property="BackgroundImageSource" Value="background_image.png" />
</Style>
</ResourceDictionary>
</Application.Resources>
But we couldn't set the AspectFill property for it while Aspect is specifically a property of the Image control as jason said.
Of course,if you need a solution that allows you to change the AspectRatio and adjust the image you can use this:
<?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="Pages.PhotoPage">
<Grid >
<Image Source="background.png" Aspect="AspectFit" />
<!-- Place here the rest of the layout for the page. -->
</Grid >
</ContentPage>
Or use the solution j-petty said:
<AbsoluteLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Image AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0, 0, 1, 1" Source="sample.jpg" Aspect="AspectFill"/>
<StackLayout AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="1,1,1,1">
<!--Content-->
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" >
<Label x:Name="KategoriePicker" Text="Was möchtest du essen?" BackgroundColor="White" />
<Label x:Name="OrtTextBox" Text="Dein Lieferort" BackgroundColor="White" />
</StackLayout>
</StackLayout>
</AbsoluteLayout>

How can I create a new Xamarin Element based on a Frame with a StackLayout inside of it?

I have a Frame with a StackLayout inside of it:
<Frame CornerRadius="1" HasShadow="false" Margin="10"
BackgroundColor="White" BorderColor="Silver" Padding="0" >
<StackLayout Orientation="Vertical" Spacing="0" Padding="0" >
<xaml:PtiXaml />
<template:LineTemplate />
<xaml:AtiXaml />
<template:LineTemplate />
<xaml:StiXaml />
</StackLayout>
</Frame>
Can I create a new object called NewFrame that is the same as the Frame with the StackLayout inside?
<template:NewFrame>
<xaml:PtiXaml />
<template:LineTemplate />
<xaml:AtiXaml />
<template:LineTemplate />
<xaml:StiXaml />
</template:NewFrame>
or
<template:NewFrame>
<xaml:ABCXaml />
</template:NewFrame>
or
<template:NewFrame>
<Label Text="X" />
</template:NewFrame>
It was suggested I use a Custom View but I have looked and can not find an example of this where it contains other elements inside.
Right-Click at the desired position in your Shared Project (or PCL) in your Solution Explorer (I would recommend adding a folder named "Views" or "CustomViews" and creating the item inside that folder), select "Add new item" and choose "Content View" (without (C#) behind it. The filename should be something like "View1.xaml", you can change that due to your liking, however the important thing is that the xaml extension is there.
This will create a new ContentView with a xaml and xaml.cs file.
Inside the xaml file you can declare your xaml code posted above and write any code necessary into the xaml.cs file.
Now you can add a namespace declaration to the page you want to put your view into:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
...
xmlns:customs="clr-namespace:YourNamespace.Views;assembly=YourNamespace"
and declare the element in that Page's or any layout's content:
<customs:CustomViewName ... />
If you want to be able to control the element's behaviour you can add BindableProperties in the codebehind.
For more in-depth information on that, you might want to take a look into this article: https://visualstudiomagazine.com/articles/2017/10/01/add-custom-controls.aspx
Use a ContentView along with a ControlTemplate to create a Custom Control. This way you can create a new control called NewFrame, write the XAML for your control and then use the <ContentPresenter> tag inside your <ControlTemplate> to assign where you'd like your content to be.
Like so:
.
└── NewFrame
├── NewFrame.cs
└── NewFrame.xaml -> Is a ResourceDictionary
NewFrame.cs:
namespace TestApp.Controls
{
public partial class NewFrame : ContentView
{
}
}
NewFrame.xaml:
<ResourceDictionary
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:newFrame="clr-namespace:TestApp.Controls"
x:Class="Namespace.For.A.ResourceDictionary">
<Style TargetType="newFrame:NewFrame">
<Setter Property="ControlTemplate">
<Setter.Value>
<ControlTemplate>
<ContentView BackgroundColor="Transparent">
<Frame CornerRadius="1" HasShadow="false" Margin="10" BackgroundColor="White" BorderColor="Silver" Padding="0" >
<StackLayout Orientation="Vertical" Spacing="0" Padding="0">
<ContentPresenter/>
</StackLayout>
</Frame>
</ContentView>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
ConsumingYourControl.xaml:
<template:NewFrame>
<template:NewFrame.Content>
<xaml:PtiXaml />
<template:LineTemplate />
<xaml:AtiXaml />
<template:LineTemplate />
<xaml:StiXaml />
</template:NewFrame.Content>
</template:NewFrame>
<template:NewFrame>
<template:NewFrame.Content>
<xaml:ABCXaml />
</template:NewFrame.Content>
</template:NewFrame>
<template:NewFrame>
<template:NewFrame.Content>
<Label Text=""/>
</template:NewFrame.Content>
</template:NewFrame>

Can I use something like a control template in Xamarin to surround a new object?

My application has objects that are surrounded by this:
<StackLayout HeightRequest="49" BackgroundColor="Red" Orientation="Vertical" Margin="0" >
<Grid VerticalOptions="CenterAndExpand">
     <!-- XAML here -->
    </Grid>
</StackLayout>
I would like to make it so that I don't need to enter the XAML on the 1st, 2nd, last and next to last lines each time.
Can I use something like a control template to avoid doing this and if so how would I use it?
You will need to use a combination of ContentPresenter and ControlTemplate (as mentioned in the note on this page)
On a ContentPage (or ContentView), the Content property can be assigned and the ControlTemplate property can also be set. When this occurs, if the ControlTemplate contains a ContentPresenter instance, the content assigned to the Content property will be presented by the ContentPresenter within the ControlTemplate.
<ControlTemplate x:Key="DefaultTemplate">
<StackLayout HeightRequest="49" BackgroundColor="Red"
Orientation="Vertical" Margin="0">
<Grid VerticalOptions="CenterAndExpand">
<ContentPresenter /> <!-- This line is replaced by actual content -->
</Grid>
</StackLayout>
</ControlTemplate>
Usage:
<ContentView ControlTemplate="{StaticResource DefaultTemplate}">
<!-- XAML here (basically the view that is to be surrounded by above layout) -->
<Label TextColor="Yellow" Text="I represent the content" />
</ContentView>
Yes, Xamarin also provide the Control Template functionalities in XAML.
Write a below code in App.xaml
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="TealTemplate">
<Grid>
<Label Text="Control Template Demo App"
TextColor="White"
VerticalOptions="Center" />
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
Call the template in side ContentPage
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.HomePage">
<ContentView x:Name="contentView" Padding="0,20,0,0"
ControlTemplate="{StaticResource TealTemplate}">
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="Welcome to the app!" HorizontalOptions="Center" />
<Button Text="Change Theme" Clicked="OnButtonClicked" />
</StackLayout>
</ContentView>
</ContentPage>

Bind to ContentPage Title From ControlTemplate

I have a fairly simple Xamarin.Forms App, with a ContentPage and a ControlTemplate in an App.Xaml ResourceDictionary
I am trying to bind to the ContentPage.Title Property of the parent ContentPage. however the following doesn't seem to work..
ContentPage
<ContentPage
x:Class="Inhouse.Mobile.Pcl.Views.MoveLocationView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
ControlTemplate="{StaticResource MainPageTemplate}"
Title="Move Location"
...
ControlTemplate
<?xml version="1.0" encoding="utf-8" ?>
<Application
x:Class="Inhouse.Mobile.Pcl.App"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="MainPageTemplate">
<cut for Brevity ...>
<StackLayout BackgroundColor="#333333">
<Label Text="{TemplateBinding Page.Title}"></Label>
</StackLayout>
<ScrollView Grid.Row="2" >
<ContentPresenter VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" />
</ScrollView>
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
I'm not sure what i should actually be binding too
i.e my attempt was
<Label Text="{TemplateBinding Page.Title}"></Label>
My problem was that i was in a StackLayout and needed to set
HorizontalOptions="StartAndExpand" so i could see it.
Additionally, Title was sufficient
{TemplateBinding Title}
I.e
<StackLayout Grid.Row="1" BackgroundColor="#333333">
<Label Text="{TemplateBinding Title}" TextColor="AliceBlue" HorizontalOptions="StartAndExpand"/>
</StackLayout>

how to define/override Style for ContentView when it is child of ContentPage

I have contentview as below
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:convertors="clr-namespace:myApp.Convertors;assembly=myApp"
x:Class="myApp.cwPart">
<ContentView.Content>
<StackLayout Orientation="Horizontal"
BackgroundColor="White">
<RelativeLayout Style="{StaticResource myStyle}"
HorizontalOptions="Start"
VerticalOptions="Center">
I am referencing this ContentView inside multiple ContentPages as example one below. Every ContentPage should set different BackgroundColor, Height and Width. That's why I thought that style should be defined in the ContentPage but it is throwing error that it is not recognized. How can I achieve this?
PS, interesting thing I am using Gorilla player to achieve such changes and Gorilla player doesn't return any error :)
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:convertors="clr-namespace:myApp.Convertors;assembly=myApp"
xmlns:c="clr-namespace:myApp;assembly=myApp"
x:Class="myApp.AppLogsPage"
Title="{Binding AppName}"
x:Name="AppLogsPage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="myStyle" TargetType="RelativeLayout">
<Setter Property="HeightRequest" Value="148"/>
<Setter Property="WidthRequest" Value="80"/>
<Setter Property="BackgroundColor" Value="White"/>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout x:Name="MainHolder">
<c:cwPart />
...
If I define ContentView Resources as below, it works fine but I am not able to override the Style defined inside ContentView
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:convertors="clr-namespace:myApp.Convertors;assembly=myApp"
x:Class="myApp.cwPart">
<ContentView.Resources>
<ResourceDictionary>
<Style x:Key="myStyle" TargetType="RelativeLayout">
<Setter Property="HeightRequest" Value="148"/>
<Setter Property="WidthRequest" Value="80"/>
<Setter Property="BackgroundColor" Value="White"/>
</Style>
</ResourceDictionary>
</ContentView.Resources>
<ContentView.Content>
<StackLayout Orientation="Horizontal" BackgroundColor="White">
<RelativeLayout Style="{StaticResource myStyle}"
HorizontalOptions="Start" VerticalOptions="Center" >
There are many issues i would change in your approach but let's keep it simple. First of all i would use contentview with control template as;
in App.xaml;
<ControlTemplate x:Key="MyControlTemplate">
<StackLayout Orientation="Horizontal" BackgroundColor="White">
<RelativeLayout HorizontalOptions="Start" VerticalOptions="Center" />
</StackLayout>
</ControlTemplate>
then in your page.xaml
<ContentView ControlTemplate={StaticResource MyControlTemplate}/>
if you want to set individual styles for every page then you can create a control template for each of them.
To create a WPF like user control;
in App.xaml;
<ControlTemplate x:Key="MyControlTemplate">
<StackLayout Orientation="Horizontal" BackgroundColor="White">
<RelativeLayout HorizontalOptions="Start" VerticalOptions="Center" />
</StackLayout>
</ControlTemplate>
in the same project
public class CustomView: ContentView
{
public CustomView()
{
ControlTemplate = (ControlTemplate)Application.Current.Resources.FirstOrDefault(x => x.Key == "MyControlTemplate").Value;
}
}
then you can use CustomView control/view in any xaml page. Don't forget to add xaml namespace of the CustomView in consuming xaml page.

Resources