xamarin.forms XAML CODE TO MINIMIZE DISTANCE BETWEEN Label and button - xaml

I am developing a xamarin.forms app and here as shown in the images I am getting wide vertical spacing between label field and buttons, so I need to decrease them and align them in proper order, here is the XAML code so please suggest me what changes do I need to make?
<ScrollView>
<StackLayout Padding="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".3*"></ColumnDefinition>
<ColumnDefinition Width=".5*"></ColumnDefinition>
<ColumnDefinition Width=".2*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
>
<Label Text="Name" Grid.Column="0" Grid.Row="4" Style="
{DynamicResource SizedLabel}" TextColor="Black"
VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"
HorizontalTextAlignment="Start"/>
<Entry x:Name="name" Grid.Column="1" Grid.Row="4"
Placeholder="" WidthRequest="100" FontAttributes="None" FontSize="Small"
BackgroundColor="Transparent" VerticalOptions="CenterAndExpand"
HorizontalOptions="FillAndExpand"></Entry>
<Label x:Name="qty_lbl" Text=" Quantity"
Grid.Column="0" Grid.Row="5" Style="{DynamicResource SizedLabel}"
TextColor="Black" VerticalOptions="CenterAndExpand"
HorizontalOptions="StartAndExpand" HorizontalTextAlignment="Start"/>
**<Entry x:Name="quantity" Grid.Column="1" Grid.Row="6"
Keyboard="Numeric" Placeholder="" WidthRequest="100"
FontAttributes="None" FontSize="Small" BackgroundColor="Transparent"
VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
</Entry>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".1*"></ColumnDefinition>
<ColumnDefinition Width=".1*"></ColumnDefinition>
<ColumnDefinition Width=".1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Button x:Name="save_btn" BackgroundColor="DodgerBlue"
Grid.Column="0" Grid.Row="1" TextColor="White" Text="Next/Save"
Clicked="OnSave" BorderColor="Black"/>
<Button x:Name="cancel_btn" BackgroundColor="DodgerBlue"
Grid.Column="1" Grid.Row="1" TextColor="White" Text="Cancel"
Clicked="OnCancel" BorderColor="Black"/>
<Button x:Name="close_btn" BackgroundColor="DodgerBlue"
Grid.Column="2" Grid.Row="1" TextColor="White" Text="Close"
Clicked="OnClose" BorderColor="Black"/>
</Grid>**
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<StackLayout Orientation="Horizontal" HeightRequest="40"
HorizontalOptions="FillAndExpand" Grid.Column="0" Grid.Row="0"
BackgroundColor="LightGray">
<Label x:Name="count_label" Text="" Style="
{DynamicResource SizedLabel}" TextColor="Gray"
HorizontalTextAlignment="Start" VerticalOptions="CenterAndExpand"
HorizontalOptions="FillAndExpand"></Label>
</StackLayout>
</Grid>
</StackLayout>
</ScrollView>
</StackLayout>
To make the buttons move up what changes do I need to make?
thanks

The problem lays in the use you make of the Grid.Row attached property. In the first grid, you define 2 rows but, then, you assign to some of its children controls the property Grid.Row to 4, 5 and 6. This implicitly force the creation of additional rows, and you end up with a grid with 7 rows (because of course rows are 0 based).
When the rows aren't given an explicit height, they are given "*", which means "equally proportional", that is, all of the same size. That's alone create a lot of extra space.
Also, in the second Grid, the one with the buttons, you define it with only one row, but assign Grid.Row = "1" to all the three buttons, this way forcing the creation of a second row. Again, because you don't specify an height, the newly created row has the same size of the row containing the buttons.
To fix all this you have to:
Assign Grid.Row = "0" to the first Label and the first Entry.
Assign Grid.Row="1" to the second Label and the second Entry.
Assign Grid.Row="0" to all the three buttons.
If you instead want the labels to appear over the relative entry, then assign Grid.Row = "0" to the first Label, Grid.Row = "1" to the first Entry, Grid.Row = "2" to the second Label and Grid.Row = "3" to the second Entry.
Also, for clarity, define four Rows in the Grid, with Height="Auto" or Height="*".
To make your code more concise, please note:
0 is the default for both Grid.Row and Grid.Column, so you can get rid of such assignments;
You don't have to define a Grid.RowDefinitions property if your Grid has only one row. The same, you don't have to define a Grid.ColumnDefinitions property if your Grid has only one column.
There is no use in using decimal notation when expressing height or width with "*" values. Star values indicate a proportion between rows (or columns), so for example if a row is "2*" and a second row is "*", the first row will be twice as tall than the second. The sum of the stars assigned to the rows (or the columns) can be any number, because it has no particular meaning, what is important is only the relative proportions between rows (or columns). To clarify even more, in the example made before, you could have assigned "100*" to the first row and "50* to the second: the result would have been the same.

Related

Updating Labels within Grid from ObservableCollection

I am currently working with an app in Xamarin, building it for UWP.
In this app, I have a Stack that has an image of the human body with other images overlayed (colored circles). What I am trying to do is place a Label on top of the circles on the body and update them in real time based on data within an ObservableCollection (called TagInfoList) I am pulling from another file. To set this up, I have made a 5x4 Grid that the Body image takes up the entirety of, and have placed the circles within individual cells of the Grid. Additionally, the Labels go in their own cells. The issue I am running into is getting my Labels to show up and actively update from my TagInfoList.
Here is what I am trying to set up. I want my Labels to go on top of the colored circles.
Here is the XAML code:
<StackLayout Orientation="Horizontal" HorizontalOptions="EndAndExpand"> <!-- Body Model Section -->
<Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" WidthRequest="400" ColumnSpacing="0">
<Grid.ColumnDefinitions> <!-- 4 equal size Columns-->
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions> <!-- 5 equal size Rows -->
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Image Source="{pages:ImageResource BLE.Client.Pages.body.png}" Aspect="AspectFit" Grid.Row="0" Grid.Column="0" Grid.RowSpan="5" Grid.ColumnSpan="4"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.green.png}" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.red.png}" Grid.Row="2" Grid.Column="0" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.green.png}" Grid.Row="2" Grid.Column="3" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.green.png}" Grid.Row="4" Grid.Column="1" Aspect="AspectFit" Opacity="0.6"/>
<Image Source="{pages:ImageResource BLE.Client.Pages.red.png}" Grid.Row="4" Grid.Column="2" Aspect="AspectFit" Opacity="0.6"/>
<CollectionView ItemsSource="{Binding TagInfoList}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center" Grid.ColumnSpan="2"/>
<Label Grid.Row="2" Grid.Column="0" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
<Label Grid.Row="2" Grid.Column="3" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
<Label Grid.Row="4" Grid.Column="1" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
<Label Grid.Row="4" Grid.Column="2" Text="{Binding SensorAvgValue}" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Center"/>
</ViewCell>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</StackLayout> <!-- Body Model Section -->
I've tried putting the Labels within a CollectionView since I can bind it to the TagInfoList, something a Grid cannot do. However, I am unsure what changes I need to make with the hierarchy of my objects to get the Labels to actively update. The TagInfoList and SensorAvgValue that I am calling are both updating correctly in other StackLayout instances, so I know there is no issue with the ObservableCollection.
In addition, my next step will be to make the Images change based on the value in the Label, so I may need to also move the Image objects to whatever level the Labels are at so they can interact with each other.
If this would be easier to do in a .xaml.cs file, I could also transfer the code to one. One exists but it's only there for one part of a different Stack in my layout.
Any and all advice would be appreciated. Thank you all!
So as the user Jason mentioned: a mockup would be nice. anyway...
If you just want an Image and a batch over it, wrap it into a "BatchView".
Another easy way would be if you place all (Image, Label, Batch(?)) into an "AbsolutLayout" and then Position it, as the AbsolutLayout is like an overlay.
Finally set it all to a Binding with OnPropertyChanged, so it will update itself like in a CollectionView - in a CollectionView it's the same mechanism but automated.
Just draw an simple mockup and post ;)

Rectangle in Xamarin forms does not honor the HeightRequest

I am trying to set the HeightRequest of a Rectangle to 10, but the height instead fills the entire height of the Grid. What am I doing wrong or is this a bug in Xamarin Forms. I am using Xamarin.Forms 5.0.0.2012.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<shapes:Rectangle Grid.Row="0" Grid.Column="0"
Fill="Green"
StrokeThickness="0"
WidthRequest="50"
HeightRequest="10"/>
<Label Grid.Row="0" Grid.Column="1"
Style="{StaticResource Subtitle1TextStyle}"
Text="Green area: ideally, your average lines would stay within your target range." />
<shapes:Rectangle Grid.Row="1" Grid.Column="0"
Fill="Black"
StrokeThickness="0"
WidthRequest="50"
HeightRequest="10"/>
<Label Grid.Row="1" Grid.Column="1"
Style="{StaticResource Subtitle1TextStyle}"
Text="Black line: The black line has a lot of text on this line. The Rectangle height keeps growing even though the height request has been set to 10." />
</Grid>
Because you are putting the Label and the black rectangle on the same Row (which have it Height set to Auto), it means it will take the maximum Height of the elements in that Row which in your case is the Label, thus the rectangle will get the same Height as the Label even that you have specified it HeightRequestto be 10.
To overcome this create another Row and span the Label over Row 2 and 3, also notice the new simplified syntax for ColumnDefinition and RowDefinition:
<Grid RowDefinitions="auto,auto,auto" ColumnDefinitions="auto,*">
<Rectangle Grid.Row="0" Grid.Column="0"
Fill="Green"
StrokeThickness="0"
WidthRequest="50"
HeightRequest="10"/>
<Label Grid.Row="0" Grid.Column="1"
Text="Green area: ideally, your average lines would stay within your target range."/>
<Rectangle Grid.Row="1" Grid.Column="0"
Fill="Black"
VerticalOptions="Fill"
StrokeThickness="0"
WidthRequest="50"
HeightRequest="10"/>
<Label Grid.Row="1" Grid.Column="1"
Grid.RowSpan="2"
TextColor="Black"
Text="Black line: The black line has a lot of text on this line. The Rectangle height keeps growing even though the height request has been set to 10."/>
</Grid>

How to make FlexLayout's height adjust to its content?

In my Xamarin Forms application, I have a list of strings (minimum 1, maximum 4) that I want to display evenly in a column layout. Each column needs to have the same width and the content should expand so that the whole text is wrapped and visible. I know how I can do it using the Grid control using Width="*" on its columns.
I want to achieve the same result using FlexLayout, so I can bind the list of strings to BindableLayout and easily add and remove columns (I will not be displaying strings but a more complex layout in each column).
Using FlexLayout.Grow and FlexLayout.Basis I can get the FlexLayout to display evenly sized columns. The problem is making the FlexLayout's height fit all the displayed labels. Only the first row of text is displayed.
Both the Grid and FlexLayout are wrapped in a StackLayout:
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="First label" Grid.Column="0" BackgroundColor="Aqua"
LineBreakMode="WordWrap" />
<Label Text="Second label" Grid.Column="1" BackgroundColor="Red"
LineBreakMode="WordWrap" />
<Label Text="Third label but with longer text" Grid.Column="2" BackgroundColor="Aqua"
LineBreakMode="WordWrap"/>
<Label Text="Fourth label" BackgroundColor="Red"
Grid.Column="3" LineBreakMode="WordWrap" />
</Grid>
<BoxView BackgroundColor="Blue"></BoxView>
<FlexLayout AlignItems="Stretch">
<Label Text="First label"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Aqua"
LineBreakMode="WordWrap" />
<Label Text="Second label"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Red"
LineBreakMode="WordWrap" />
<Label Text="Third label but with longer text"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Aqua"
VerticalOptions="FillAndExpand"
LineBreakMode="WordWrap" />
<Label Text="Fourth label"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Red"
LineBreakMode="WordWrap" />
</FlexLayout>
<BoxView BackgroundColor="Blue"></BoxView>
</StackLayout>
Grid and FlexLayout displayed
I figured out that when setting the HeightRequest of the FlexLayout to a specific number (e.g. 150), everything works as expected - the row has a height of 150 and all the labels stretch out to fit that. So what I need is somehow specify HeightRequest="Auto" so that the row fits all the column's content without being set to a specific value
Is there a way to achieve this?
FlexLayout will cut its child Elements . So in your case use Grid is the best solution .
so I can bind the list of strings to BindableLayout and easily add and remove columns
If you want to display a collection of data I suggest that you could use ListView or CollectionView(if you want to let the collection scroll in Horizontal or display multi Columns in the same row) .
<ContentPage.Resources>
<ResourceDictionary>
<local:WidthConverter x:Key="WidthConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout x:Name="stack">
<CollectionView x:Name="list" >
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid WidthRequest="{Binding Source={x:Reference stack},Path=Width,Converter={StaticResource WidthConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Text="111111" BackgroundColor="LightBlue" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
in code behind
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var width = (double)value;
if(width>0)
{
return width * 0.25;
}
return 100;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return 0;
}
}
For more details you could check https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/layout#horizontal-list

Xamarin forms vertically center text over image

I'm learning Xamarin and I want to display an image as background with some texto over this image...
Just that, I manage to acomplish, but the text is displayed at the top left corner of the image.
I'd like the text to be placed at the vertical center of the image, but stick to the left side of it.
My code so far XAML:
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="20*" ></RowDefinition>
<RowDefinition Height="65*"></RowDefinition>
<RowDefinition Height="15*"></RowDefinition>
</Grid.RowDefinitions>
<RelativeLayout Grid.Row="0">
<Image Source="login.png" Aspect="Fill" />
<Label Text="Bem vindo" TextColor="White" FontSize="22"></Label>
</RelativeLayout>
<Label Grid.Row="1" Text="linha 2" BackgroundColor="Coral"></Label>
<Button Grid.Row="2" Text="linha 3" BackgroundColor="DarkRed"></Button>
</Grid>
I've tried verticalOptions and such, but with no effect.
One thing that kind of worked is settin a Maring property to the label, but that way, the label would be centered only to the device I'm testing on. Other devices, smaller or greater, the label could (and probably would) be placed at the wrong place.
Any help?
You don't need a RelativeLayout inside the Grid. The Grid itself already is able to handle views overlay besides let your code clearer.
It may works:
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="20*"></RowDefinition>
<RowDefinition Height="65*"></RowDefinition>
<RowDefinition Height="15*"></RowDefinition>
</Grid.RowDefinitions>
<Image Grid.Row="0" Grid.Column="0"
Source="login.png"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Aspect="Fill" />
<Label Grid.Row="0" Grid.Column="0"
Text="Bem vindo"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
HorizontalTextAlignment="Start"
VerticalTextAlignment="Center"
TextColor="White"
FontSize="22"/>
<Label Grid.Row="1"
Text="linha 2"
BackgroundColor="Coral"/>
<Button Grid.Row="2"
Text="linha 3"
BackgroundColor="DarkRed"/>
</Grid>

Dynamically expanding Grid also expands fixed height Rows and Columns

I have a dynamically expanding Grid inside another Grid which is separated onto 4 rows and 4 columns.
My main content grid spans 4 rows and 2 columns and dynamically loads different Views, and sometimes expands in height. My problem is, the other rows are also expanded although they have a fixed height, which makes the layout appear weird.
I want to keep all the rows' heights to 36, but just expand the lowest row so all content of my grid is shown.
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="45" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="70" />
<ColumnDefinition Width="110" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="36" />
<RowDefinition Height="36" />
<RowDefinition Height="36" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
FontSize="14"
Content="X">
</Button>
<Grid x:Name="MainPaymentContentRoot"
Grid.Row="0"
Grid.RowSpan="4"
Grid.Column="1"
Grid.ColumnSpan="2"
Margin="20,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollMode="Auto">
</Grid>
<TextBlock Text="MyField" Grid.Row="0" Grid.Column="3" Margin="10,0,0,0" VerticalAlignment="Center" />
<Button Grid.Row="1" Grid.Column="3" Margin="10,0,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Right"
Content="AnotherButton">
</Button>
</Grid>
This is for a Win 8 Development.
Currently, your RowDefinition is set to Auto. This means that the row will calculate the content size, and adjust it's height accordingly.
You need to change it to Height="*".
<RowDefinition Height="*" />
This will force the RowDefinition to expand to the height of the parent. In other words, it will take up all available space.