Unexpected Stack Layout behavior in xamarin - xaml

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>

Related

AbsoluteLayout with proportional height and with minimum and maximum heights

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>

keyboard popup its hide last row of grid

I have using AppCompact Themes in xamarin forms android when keyboard popup its hide last row of grid
Before Keyboard Popup see Image
Below is my code. I've created the grid having title, description. I want to show the camera icon and its bar above the keyboard when it comes and go back to the bottom of the screen when the keyboard hides.
<Grid RowSpacing="0" VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="80" />
<RowDefinition Height="*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<StackLayout
Grid.Row="0"
Padding="10,8"
BackgroundColor="White"
HorizontalOptions="FillAndExpand"
Orientation="Horizontal">
<Entry
x:Name="GeneralPostTitle"
Margin="10,10,10,0"
FontSize="20"
HorizontalOptions="FillAndExpand"
Placeholder="Title"
PlaceholderColor="Gray"
TextColor="Black"
VerticalOptions="End" />
</StackLayout>
<StackLayout
Grid.Row="1"
Padding="10,0"
BackgroundColor="White"
HorizontalOptions="FillAndExpand"
Spacing="0"
VerticalOptions="FillAndExpand">
<StackLayout Padding="0" VerticalOptions="Fill">
<customRenderer:PlaceholderEditor
x:Name="EditorDescription"
Margin="10,10,10,0"
FontSize="22"
HeightRequest="130"
HorizontalOptions="Fill"
Placeholder="Add Description"
PlaceholderTextColor="Gray"
TextColor="Gray" />
</StackLayout>
<ScrollView Padding="10" Orientation="Horizontal">
<StackLayout
x:Name="Images"
HorizontalOptions="FillAndExpand"
Orientation="Horizontal"
Spacing="5" />
</ScrollView>
</StackLayout>
<StackLayout
Grid.Row="2"
Padding="20,0"
BackgroundColor="#FAFAFA">
<Image
Aspect="AspectFit"
HeightRequest="40"
HorizontalOptions="StartAndExpand"
WidthRequest="30">
<Image.Source>
<OnPlatform
x:TypeArguments="ImageSource"
Android="camera"
WinPhone="Icons/camera.png"
iOS="Icons/camera.png" />
</Image.Source>
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="ImagePost_OnTapped" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</Grid>
After Keyboard Popup see Image
You need to set SoftInput to AdjustResize in order for Android to resize the views so they stay visible. In Forms, you can do this with the platform specifics feature in Forms 2.3.3.
Check out this Gist on how to do this in OnCreate(). Note the workaround that's needed to remove an underlay added to the status bar in API 21+.

How to adjust scroll height of Xaml StackLayout?

I have a StackLayout which has items dynamically added to it when a user is selected. I want it to have a height of around 200, then if the list is longer than this, it should be scrollable.
If I add a height request to it as it is now, it adjusts the height and the scrollbar works but prevents items being added after the bottom of the box (so the scrollbar is basically pointless.
This is the code, the StackLayout is called 'readout':
<?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="Clocker.MainPage" >
<StackLayout x:Name="mainstack">
<Picker x:Name="locationpicker" SelectedIndexChanged="locationpicker_SelectedIndexChanged" BackgroundColor="#baf4d5"></Picker>
<Label x:Name="timeLabel" FontSize="50" HorizontalTextAlignment="Center" VerticalTextAlignment="Start" TextColor="White" BackgroundColor="#59a092"/>
<ScrollView Orientation="Vertical" BackgroundColor="#baf4d5">
<StackLayout x:Name="readOut">
</StackLayout>
</ScrollView>
<ListView x:Name="userslist" BackgroundColor="#59a092">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Clicked="OnIn" CommandParameter="{Binding .}"
Text="In" />
<MenuItem Clicked="OnOut" CommandParameter="{Binding .}"
Text="Out" IsDestructive="True" />
</ViewCell.ContextActions>
<StackLayout Padding="15,0">
<Label x:Name="lblname" Text="{Binding FullName}" TextColor="White" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
I've 2 or 3 pages in my app that are more or less like what you described.
My solution uses and 2 lists.
More or less like this:
<Grid ColumnSpacing="0" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2*" />
<RowDefinition Height="8*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
Row 1 is where I have my first list, row 2 is where the second list goes.
I do it this way (0 is a header and 3 is a footer), so I have more or less 20% of the left space on top and the rest of the space allocated for the second list.
Hope it's clear.

Create overlaying loader on a mobile app using xamarin forms

I am using Xamarin forms and am trying to create an overlaying loader for my screens. From my findings, I need to use an absolute layout, which I have done. I have accomplished for the loader to work on some screens however when the screen is a little more complex (using nested scrollviews, grids, etc.) it doesn't seem to work. Below is a sample of the code that DOES work:
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout Padding="10" Orientation="Vertical" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
<StackLayout Padding="0,85,0,0">
<Image Source="myimage.png" HorizontalOptions="Center" VerticalOptions="Start" />
</StackLayout>
<StackLayout Orientation="Vertical" Padding="10, 5, 10, 5" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Label Text="This works perfect"></Label>
</StackLayout>
</StackLayout>
<!-- Loader -->
<ContentView BackgroundColor="#222222"
Opacity="0.3"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
IsVisible="{Binding IsIndicatorActive}">
<ActivityIndicator AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
VerticalOptions="{StaticResource LoaderPosition}"
HorizontalOptions="{StaticResource LoaderPosition}"
IsEnabled="{Binding IsIndicatorActive}"
IsRunning="{Binding IsIndicatorActive}"
IsVisible="{Binding IsIndicatorActive}" />
</ContentView>
</AbsoluteLayout>
The following code is what DOESN'T work:
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout Orientation="Vertical" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
<ScrollView>
<StackLayout Padding="0,85,0,0">
<Image Source="myimage.png" HorizontalOptions="Center" VerticalOptions="Start" />
</StackLayout>
<StackLayout Orientation="Vertical" Padding="10, 5, 10, 5" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Label Text="This doesn't work"></Label>
</StackLayout>
</ScrollView>
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="EndAndExpand" ColumnSpacing="0" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" HorizontalOptions="FillAndExpand" Text="Button1" Command="{Binding Button2Command}" />
<Button Grid.Row="0" Grid.Column="1" HorizontalOptions="FillAndExpand" Text="Button2" Command="{Binding Button2Command}" />
</Grid>
</StackLayout>
<!-- Loader -->
<ContentView BackgroundColor="#222222"
Opacity="0.3"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
IsVisible="{Binding IsIndicatorActive}">
<ActivityIndicator AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
VerticalOptions="{StaticResource LoaderPosition}"
HorizontalOptions="{StaticResource LoaderPosition}"
IsEnabled="{Binding IsIndicatorActive}"
IsRunning="{Binding IsIndicatorActive}"
IsVisible="{Binding IsIndicatorActive}" />
</ContentView>
</AbsoluteLayout>
From my understanding it has something to do with the fact that scrollviews and gridviews are Managed Layouts and absolute layouts are Unmanaged Layouts so I figured if i put a stacklayout occupying the full absolute layout and afterwards the scrollview and gridview instide the stacklayout it would be relative to its parent (the way html handles this). Clearly this isn't handled in such manner (instead i just get a blank screen), which is leaving me stumped as to how I would go about this issue.
Any ideas how I can get around this issue and have my loader display without affecting my screen display? Thanks!
Maybe this will be easier:
https://components.xamarin.com/view/andhud
https://components.xamarin.com/view/btprogresshud
To implement those you only need to use the Dependency Service:
iOS implementation:
http://pastie.org/10821570
Android Implementation:
http://pastie.org/10821571
Interface implementation:
using System;
namespace YourNameSpace
{
public interface IHudService
{
void ShowHud(string ProgressText = "Loading...");
void HideHud();
void SetText(string Text);
void SetProgress(double Progress, string ProgressText = "");
}
}
And to use it simply use:
DependencyService.Get<IHudService>().ShowHud();
//Your Task...
DependencyService.Get<IHudService>().HideHud();

Scrollview scrolls up-and-over other content when scrolling

When layin out this form, I want a header the size of its content, footer the size of the content, and a middle that expands to take up the rest. Easy in XAML/UWP. But in Xamarin Forms when the ScrollView content has data it floats and overlays the top and bottom. Also when I drag/scroll the ScrollView it can go to the top of the screen. How to dock the scrollview properly so I have a scrolling middle region? Thx...
Pictures and XAML layout below....
<?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="BaseProject.MainPage">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TableView Grid.Row="0" Intent="Settings" BackgroundColor="Blue" HeightRequest="150" >
<TableSection Title="Search">
<ViewCell>
<Button x:Name="Button_Search" Text="Go"/>
</ViewCell>
<EntryCell x:Name="Entry_Cell_SearchFor" />
</TableSection>
</TableView>
<ScrollView Grid.Row="1" VerticalOptions="FillAndExpand" Orientation="Vertical">
<StackLayout BackgroundColor="Red" >
<Label Text="body" x:Name="Label_Body" BackgroundColor="Yellow" />
</StackLayout>
</ScrollView>
<StackLayout Grid.Row="2">
<Label Text="footer"/>
</StackLayout>
</Grid>
</ContentPage>
Set IsClippedToBounds property as true of ScrollView