AbsoluteLayout with proportional height and with minimum and maximum heights - xaml

We need a banner, called bannerView in the code bellow, to shrink or expand according to the device height.
However this banner height:
cannot be smaller than 60 units
cannot be bigger than 146 units
code:
<AbsoluteLayout>
<StackLayout
Padding="0"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="SizeProportional"
HorizontalOptions="FillAndExpand">
<AbsoluteLayout
x:Name="bannerView">
<Image
AbsoluteLayout.LayoutBounds="0,0,1.05,1"
AbsoluteLayout.LayoutFlags="SizeProportional"
Aspect="AspectFill"
Source="banner.jpg">
</Image>
<Label
Margin="16,18,16,36"
AbsoluteLayout.LayoutBounds="0,1,-1,-1"
AbsoluteLayout.LayoutFlags="PositionProportional"
Text="{Binding Name}">
</Label>
<Label
Margin="16,18,16,18"
AbsoluteLayout.LayoutBounds="0,1,-1,-1"
AbsoluteLayout.LayoutFlags="PositionProportional"
Text="{Binding EmployeeId}">
</Label>
</AbsoluteLayout>
<StackLayout>
<!-- Dynamic content -->
</StackLayout>
</StackLayout>
</AbsoluteLayout>
Note: We need the outer AbsoluteLayout to add a gradient effect on the screen

Have you considered the possibility to use a FlexLayout containing the banner view element, and this one having the HeightRequest attribute binded to view model?
I used something similar as ControlTemplate to achieve a custom page's header depending on the device navigation bar height:
<FlexLayout Direction="Column" JustifyContent="Center">
<!--HEADER-->
<Grid IsVisible="{TemplateBinding BindingContext.ToolbarVisibled}" HeightRequest="{TemplateBinding BindingContext.ToolbarHeight}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".8*"/>
<ColumnDefinition Width=".2*"/>
</Grid.ColumnDefinitions>
<!--...-->
</Grid>
<!--CONTENT HERE-->
<FlexLayout Direction="Column" JustifyContent="Center">
<ContentPresenter FlexLayout.Grow="1"/>
</FlexLayout>
</FlexLayout>

Related

Unexpected Stack Layout behavior in xamarin

I have a StackLayout with a Frame, ScrollView & Button as it's child controls.
When the ScrollView content is beyond a certain Height, the ScrollView seems to push the Frame above it, squashing it. I would expect that the ScrollView as a container not push upwards the view above it, but contain its content within it.
Frame - red circle, ScrollView - Blue, ScrollView's content - light blue, Button - green
EXPECTED
<?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="Class">
<ContentPage.Content>
<StackLayout
VerticalOptions="FillAndExpand"
Orientation="Vertical">
<Frame
Padding="0"
HeightRequest="60"
WidthRequest="60"
VerticalOptions="Center"
HorizontalOptions="Center"
CornerRadius="30"
BackgroundColor="Red"/>
<ScrollView
Background="Blue"
VerticalOptions="FillAndExpand">
<StackLayout
Margin="20,5,20,0"
BackgroundColor="LightBlue"
HeightRequest="150"/>
</ScrollView>
<Button
VerticalOptions="End"
Text="Next"
BackgroundColor="Green"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Ouputs (Which is what i expect):
Then if i change the ScrollView's StackLayout content's height to 950, it then squashes the content above and it looks as below:
Why is the ScrollView pushing upwards, even when the Frame has an assigned HeightRequest. How can i resolve this?
Why is the ScrollView pushing upwards, even when the Frame has an assigned HeightRequest.
From ScrollView as a child layout, a ScrollView will often be the child of a StackLayout. A ScrollView requires a specific height to compute the difference between the height of its content and its own height, with the difference being the amount that the ScrollView can scroll its content.
So you can assign specific height to Scrollview.
<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand">
<Frame
Padding="0"
BackgroundColor="Red"
CornerRadius="30"
HeightRequest="60"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="60" />
<ScrollView
Background="Blue"
HeightRequest="150"
VerticalOptions="FillAndExpand">
<StackLayout
Margin="20,5,20,0"
BackgroundColor="LightBlue"
HeightRequest="950" />
</ScrollView>
<Button
BackgroundColor="Green"
Text="Next"
VerticalOptions="End" />
</StackLayout>
Another way is to use Gird to assign specific height for Scrollview.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Frame
Padding="0"
BackgroundColor="Red"
CornerRadius="30"
HeightRequest="60"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="60" />
<ScrollView
Grid.Row="1"
Background="Blue"
VerticalOptions="FillAndExpand">
<StackLayout
Margin="20,5,20,0"
BackgroundColor="LightBlue"
HeightRequest="950" />
</ScrollView>
<Button
Grid.Row="2"
BackgroundColor="Green"
Text="Next"
VerticalOptions="End" />
</Grid>

TapGesture won't fire when adjusted inside a layout Xamarin

So basically I have an annoying thing when I'm trying to adjust my frame inside an AbsoluteLayout such:
<AbsoluteLayout Grid.Column="4">
<Frame CornerRadius="20"
Padding="0"
BorderColor="#9f6b34"
Background="Transparent">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="fourthButton_Clicked"/>
</Frame.GestureRecognizers>
<Label Text="Classic and traditional"
Padding="35"
FontSize="40"
FontFamily="font2"
HorizontalTextAlignment="Center"
TextColor="#211717">
</Label>
</Frame>
When the code is like this it's fine but when I try to adjust the frames' position with .LayoutBounds it just won't click. I've tried changing it to a StackLayout and click event fires sometimes in various different positions inside the frame. I've put ImageButton, regular button and also tried using my label's GestureRecognizer but it just won't click when I made adjustments.
here is a gif of the situtation. the top frame isn't adjusted the bottom one is
When the code is like this it's fine but when I try to adjust the frames' position with .LayoutBounds it just won't click.
I try your code, and it works fine, having no problem, please take a look the following code:
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<AbsoluteLayout>
<Frame
Padding="0"
AbsoluteLayout.LayoutBounds="0, 10, 300, 200"
BorderColor="#9f6b34"
CornerRadius="20">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="fourthButton_Clicked" />
</Frame.GestureRecognizers>
<Label
Padding="35"
FontFamily="font2"
FontSize="40"
HorizontalTextAlignment="Center"
Text="Classic and traditional"
TextColor="#211717" />
</Frame>
</AbsoluteLayout>
<StackLayout Grid.Row="1">
<Frame
Padding="0"
BorderColor="#9f6b34"
CornerRadius="20">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="fourthButton_Clicked" />
</Frame.GestureRecognizers>
<Label
Padding="35"
FontFamily="font2"
FontSize="40"
HorizontalTextAlignment="Center"
Text="Classic and traditional"
TextColor="#211717" />
</Frame>
</StackLayout>
</Grid>
</StackLayout>
I put Frame in AbsoluteLayout and also use AbsoluteLayout.LayoutBounds to adjust Frame poaition, I also put frame in StackLayout, it also works fine.

How to separate Entry and Image using Grid within a Frame?

I'm making an Entry that has an Image on the right inside it.
The problem I have is that the text is placed behind the Image, what I want to do is that the text is cut off when it reaches the Image, separate the entry from the Image. I am using a Frame and inside it, a Grid. I have tried to put right margin to Entry but the Image is scrolling out. To do the Entry I am using the NuGet: Xamarin.Forms.Visual.Material
This is my code:
<StackLayout>
<Frame BackgroundColor="Transparent" HasShadow="False">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Entry
x:Name="entrycontrol"
BackgroundColor="{Binding Source={x:Reference ValidateView}, Path=BGColor}"
HeightRequest="60"
Visual="Material"
WidthRequest="{Binding Source={x:Reference ValidateView}, Path=Width}" />
<Image
x:Name="ImageRight"
Grid.Column="0"
Margin="0,0,5,0"
HeightRequest="25"
HorizontalOptions="End" />
</Grid>
</Frame>
</StackLayout>
The Source of the Image I establish it in the code behind.
Your main issue is that you are overlaying your Image on top of the Entry control. You need to specify a Grid.Column="1" so it uses the right hand column. A detailed explanation of how a Grid layout works can be found on Microsofts site
I would suggest that you do not need to bind the WidthRequest property for the Entry control. Plus I would swap your column definitions around. Auto means the column will grow in size, * means it will stretch to a size based on what other columns have been defined.
To summarise you want something like:
<StackLayout>
<Frame BackgroundColor="Transparent" HasShadow="False">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <!-- swapped -->
<ColumnDefinition Width="Auto" /> <!-- swapped -->
</Grid.ColumnDefinitions>
<Entry x:Name="entrycontrol"
BackgroundColor="{Binding Source={x:Reference ValidateView}, Path=BGColor}"
HeightRequest="60"
Visual="Material" />
<Image x:Name="ImageRight"
Grid.Column="1"
Margin="0,0,5,0"
HeightRequest="25"
HorizontalOptions="End" />
</Grid>
</Frame>
</StackLayout>
Better yet if you have a fixed image size then you can simply set your ColumnDefinition to that size.

Center content if text becomes bigger

i have this sample xaml:
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<StackLayout BackgroundColor="LightBlue">
<Label Text="ABC"
HorizontalTextAlignment="Center" />
<Label Text="L"
HorizontalTextAlignment="Center"></Label>
</StackLayout>
<BoxView BackgroundColor="Red" />
<StackLayout BackgroundColor="LightGreen">
<Label Text="ABC"
HorizontalTextAlignment="Center" />
<Label Text="C"
HorizontalTextAlignment="Center"></Label>
</StackLayout>
</StackLayout>
which produces this output:
But if one of the four lables becomes bigger there are not centered anymore:
My goal is the following layout, which depends on the biggest label:
I'm a beginner. So i hope somebody could help me with the correct layout.
Thanks
StackLayout really isn't the best choice here, because it occupies the size dynamically (i.e. depending on its content). What's the better approach here is to use Xamarin.Forms' Grid layout.
This way, you can have a grid with 3 columns. Then, you will set your ColumnDefinitions's width to star (*). Like you can see in the Rows and columns section, setting the column's width to star means that:
Star – leftover row height or column width is allocated proportionally (a number followed by * in XAML).
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0" /> <!-- Blue StackLayout wrapper -->
<BoxView Grid.Column="1" /> <!-- Red BoxView -->
<StackLayout Grid.Column="2" /> <!-- Green StackLayout wrapper -->
</Grid>
Basically, you will have divided the whole screen width to 3 equal parts, each resulting in an 33,3(3) % of the screen. Then, you can align the elements in the container as you wish.

Xamarin margins are different between two resolutions (devices)

I have a page in xamarin with a couple of frames, all with an image (color) and text. However, i'm facing the problem that the margins of the images (colors) look different on different phones (resolutions). As you can see on the image below, the images are in the right position on the Galaxy S8 (resolution 1440x2960) and at the wrong position on the Galaxy S10e (resolution 1080 x 2280).
I am using the following code for the frames:
<Grid ColumnSpacing="12.5" RowSpacing="12.5" Padding="10" HeightRequest="500">
<Grid.RowDefinitions>
<RowDefinition Height="0.8*" />
<RowDefinition Height="4.5*" />
<RowDefinition Height="1.5*" />
<RowDefinition Height="1.5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Frame x:Name="frame_Sport" Grid.Row="2" Grid.Column="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="Sport_Clicked"/>
</Frame.GestureRecognizers>
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" >
<Label Text=" Sport" FontSize="18"/>
</StackLayout>
<StackLayout Orientation="Vertical" >
<Label x:Name="txt_Sport" FontSize="18"/>
</StackLayout>
<Image Source="mark_green.png" Scale="0.17" Margin="-110,-137,0,0"/>
</StackLayout>
</Frame>
<Frame x:Name="frame_Voeding" Grid.Row="2" Grid.RowSpan="2" Grid.Column="1" >
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="Voeding_Clicked"/>
</Frame.GestureRecognizers>
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<Label Text=" Voeding" FontSize="18" />
<Label x:Name="txt_Voeding1" FontSize="18" Margin="0,-0.6"/>
<Label x:Name="txt_Voeding2" FontSize="18" Margin="0,-0.6"/>
<Label x:Name="txt_Voeding3" FontSize="18" Margin="0,-0.6"/>
<Label x:Name="txt_Voeding4" FontSize="18" Margin="0,-0.6"/>
<Label x:Name="txt_Voeding5" FontSize="18" Margin="0,-0.6"/>
<Label x:Name="txt_Voeding6" FontSize="18" Margin="0,-0.6"/>
<Image Source="mark_red.png" Scale="0.17" Margin="-110,-280,0,0"/>
</StackLayout>
</Frame>
<Frame x:Name="frame_Slaap" Grid.Row="3" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="Slaap_Clicked"/>
</Frame.GestureRecognizers>
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" >
<Label Text=" Slaap" FontSize="18" />
</StackLayout>
<StackLayout Orientation="Vertical">
<Label x:Name="txt_Slaap" FontSize="18" />
</StackLayout>
<Image Source="mark_blue.png" Scale="0.17" Margin="-110,-137,0,0"/>
</StackLayout>
</Frame>
</Grid>
Why are the images (colors) looking different on both phones, how do I fix this?
The values for Margin are in absolute units (pixels).
The Frame which contains the StackLayout has a different absolute width on every device. Therefore your positioning of the icon will differ if the resolution or dpi differs.
In your case I would create a Horizontal Stacklayout with the Image and the label like that:
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<StackLayout Orientation="Horizontal">
<Image Source="mark_red.png" Scale="0.17"/>
<Label Text="Voeding" FontSize="18" />
</StackLayout>
<Label x:Name="txt_Voeding1" FontSize="18" Margin="0,-0.6"/>
...
</StackLayout>
I have a page in xamarin with a couple of frames, all with an image (color) and text. However, I'm facing the problem that the margins of the images (colors) look different on different phones (resolutions). As you can see on the image below, the images are in the right position on the Galaxy S8 (resolution 1440x2960) and at the wrong position on the Galaxy S10e (resolution 1080 x 2280).
The reason this is happening is that different devices have a different density. When it comes to Margin it is a double value and Xamarin Forms converts this double values into platform specific types (for eg Dp's, Points) respectively. Hence every device responds to the same margin in a different way based on its own size and density.
In the same way, density also affects the colour. The human perception for colour changes if the device has a denser pixels even though it is the same color but it looks a little different to us! Basically, The denser the pixels are in your device the more vivid the colour is to the naked eye.
Now coming back to the issue the reason your Margin is looking different is the same reason I explained above, Now to overcome this issue you might want to either remove the StackLayout use Grid instead and define a proper Column definition in a way that they align properly.
<Grid>
<Grid.ColumnDefinitions> <--<Define these as they suit you>-->
.
.
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="mark_red.png" Scale="0.17"/>
<Label Grid.Column="1" Text="Voeding" FontSize="18" />
</Grid>
Or Increase the Spacing property of the StackLayout so it adds a little extra space between the Image and the Label:
<StackLayout Orientation="Horizontal" Spacing="10"> <--<Default spacing is 6>-->
<Image Source="mark_red.png" Scale="0.17"/>
<Label Text="Voeding" FontSize="18" />
</StackLayout>
Update:
Your XAML should look like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="mark_red.png" Scale="0.17"/>
<Label Grid.Column="1" Text="Voeding" FontSize="18" />
<StackLayout Grid.Row="1" Grid.ColumnSpan="2" >
<Label x:Name="txt_Voeding1" FontSize="18" Margin="0,-3"/>
<Label x:Name="txt_Voeding2" FontSize="18" Margin="0,-3"/>
<Label x:Name="txt_Voeding3" FontSize="18" Margin="0,-3"/>
<Label x:Name="txt_Voeding4" FontSize="18" Margin="0,-3"/>
<Label x:Name="txt_Voeding5" FontSize="18" Margin="0,-3"/>
<Label x:Name="txt_Voeding6" FontSize="18" Margin="0,-3"/>
</StackLayout>
</Grid>