Understanding WidthRequest - xamarin

I want to change the WidthRequest. Thereby I noticed that this doesn't really set the width of an element. Rather it is kind of a proposal.
Example:
I have a ListView added as child to a StackLayout. I'm setting a WidthRequest for the ListView, but the result is not what I expect.
this.listView = new ListView
{
ItemsSource = new List<IconMenu>
{
// creation of some entries
// ...
},
ItemTemplate = new DataTemplate(typeof(IconMenuCell)),
RowHeight = 44,
// HERE is the problematic code!
WidthRequest = 10,
};
Content = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children = {
this.listView,
this.detailView,
},
};
This is the structure/layout of IconMenuCell:
public IconMenuCell()
{
var icon = new Image
{
Aspect = Aspect.AspectFit,
WidthRequest = 40,
};
icon.SetBinding(Image.SourceProperty, "IconSource");
this.textLabel = new Label {
TextColor = Color.Gray,
FontSize = 10,
VerticalOptions = LayoutOptions.Center,
};
this.textLabel.SetBinding(Label.TextProperty, "Text");
View = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Children =
{
icon,
this.textLabel,
},
};
}
Setting the WidthRequest to 10 doesn't make sense, because the icon itself should take 40. But here I get the smallest width for the whole list view.
There is no difference if I set WidthRequest to 60 or 120. The resulting width is the same (and not what I want).
How does WidthRequest work here? Do I have to change some LayoutOptions?

You need to specify a HorizontalOptions such as "start" or "center". The default horizontalOptions for stackLayout is FillAndExpand, so child elements like a listview will fill the entire available horizontal area even though you specify a width. This was a bad call on behalf of Microsoft because the default behavior will ignore/override a width request.
Here is a visual example: I have a picker where I set the width request to 200, which should take up about 2/3 of the horizontal space.
<StackLayout Padding="10">
<Picker x:Name="pickerRanks" WidthRequest="200" />
</StackLayout>
As you can see the width request is overridden/ignored. Then if after setting the HorizontalOptions to "Start"...
<StackLayout Padding="10">
<Picker x:Name="pickerRanks" WidthRequest="200" HorizontalOptions="Start"/>
</StackLayout>
The width request is honored. Of course I'm setting the properties in the .xaml file here, which I usually prefer but you can also set the HorizontalOptions in C# like this
pickerRanks.HorizontalOptions = LayoutOptions.Start;

WidthRequest just describes an element's desired width during the next layout cycle.
For it to work as you'd expect, 2 conditions must be satisfied:
1) the requested width is consistent with all constraits (ex. parent's width) and
2) a layout cycle is triggered.
WidthRequest: https://developer.xamarin.com/api/property/Xamarin.Forms.VisualElement.WidthRequest/
But that's complicated. I'd recommend just replacing the stack layout with a grid, and putting each element in a column of the desired width.
Grid Example: https://developer.xamarin.com/api/type/Xamarin.Forms.Grid/

Related

Xamarin Forms ScrollView scrolls automatically to the beginning when any child element is clicked

I created a Horizontal / Vertical Scrollview in Xamarin Forms that contains several types of childs like:
Labels
CustomCheckboxes
ImageViews
Pickers
Sliders
Here is my code:
ScrollView scrollTracks = new ScrollView
{
BackgroundColor = Color.Black,
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Content = layoutTracks,
Orientation = ScrollOrientation.Both
};
When I click some child elements like the CustomCheckboxes, or the Labels, or the ImageViews, the program scroll automatically the view to the beginning.
I tested this on the UWP platform.
How can I make the program to stop doing this?
Add this tag to the ScrollView solved my issue:
IsTabStop = false
Here the code:
ScrollView scrollTracks = new ScrollView
{
BackgroundColor = Color.Black,
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Content = layoutTracks,
Orientation = ScrollOrientation.Both,
IsTabStop = false
};

How can I add a text label that is vertically and horizontally centered to a Grid I create in C#

Here's what I have so far:
details.Children.Clear();
var grid = new Grid()
{
HeightRequest = 50
};
grid.Children.Add(new Label {
Text = "00"
});
details.Children.Add(grid);
But this doesn't centre the text in the Grid. Can someone give me advice on what I am doing wrong?
You should make use of VerticalOptions and HorizontalOptions, like this:
details.Children.Clear();
var grid = new Grid()
{
HeightRequest = 50
};
grid.Children.Add(new Label {
Text = "00" ,
VerticalOptions="Center"
HorizontalOptions="Center"
});
details.Children.Add(grid);
You may also apply this to your grid, if you want the grid centered.

Xamarin.Forms Sizing elements in a WrapLayout

Current:
Goal:
Attempting to implement a WrapLayout to allow for dynamic button addition in a clean horizontally adding format, as shown in the 'Goal' picture. However as seen in 'Current', the sizing of the buttons in the WrapLayout are far from ideal.
Have found through simple trial and error that using height and width requests in any of the elements (scrollView, wrapLayout, buttons) result in no change to the button formats.
HeightRequest = xx;
WidthRequest = xx;
The only way, I've found thus far, to change the sizing of the wrapLayout elements is to add a large amount of children, example:
As displayed, my understanding of how to format WrapLayout children is rather lacking. So, how to format the number of children allowed on each row and how to properly format the children of a WrapLayout?
Current implementation developed following the WrapLayout class shown in the Xamarin Developer Sample for WrapLayout
ScrollView scrollView = new ScrollView {
Margin = new Thickness(20, 20, 20, 20),
};
WrapLayout wrapLayout;
wrapLayout = new WrapLayout {
ColumnSpacing = 12,
};
scrollView.Content = wrapLayout;
wrapLayout.Children.Add(
new Button
{
Text = "9 ° (?)",
BackgroundColor = Color.Yellow,
BorderColor = Color.Black,
}
);
wrapLayout.Children.Add(
new Button
{
Text = "10.5 ° (?)",
BackgroundColor = Color.Gray,
BorderColor = Color.Black,
}
);
You should look at CollectionView Nuget Package
You can use the GridCollectionView, which is based on the WrapLayout.
There, you can either use:
UniformGrid
The number of columns arranged in each row is specified. Each column width becomes the width obtained by dividing the row width by that value. This number of columns can be set by PortraitColumns and LandscapeColumns properties.
"
AutoSpacingGrid
Once a column width is specified, each column is arranged until fitting in each row and adjusted automatically each spacing. A column width can be set by ColumnWidth property and Setting SpacingType property can change how to adjust the spacing.
An Example:
<ai:GridCollectionView
ItemsSource="{Binding ItemsSource}" TouchFeedbackColor="Yellow"
ColumnWidth="100" ColumnHeight="1.0" >
<ListView.ItemTemplate>
<DataTemplate>
<ai:ContentCell>
<Label Text="{Binding Name}" />
</ai:ContentCell>
</DataTemplate>
</ListView.ItemTemplate>
</ai:GridCollectionView>
I recommend using the AiForms.Layout package:
https://dev.to/muak_x/wraplayout-and-repeatablestacklayout-for-xamarinforms-1dck
here is the sample, and it works as we expected:
<aiforms:WrapLayout Spacing="4" UniformColumns="3" IsSquare="true" HorizontalOptions="FillAndExpand">
<BoxView Color="Red" />
<BoxView Color="Blue" />
<BoxView Color="Green" />
<BoxView Color="Black" />
<BoxView Color="Yellow" />
</aiforms:WrapLayout>
And there is a RepeatableWrapLayout with Itemtemplate and ItemsSource Binding.

how to apply max height and enable scroll to Xamarin.Forms.Editor

I wanted chat application type user interface in my app & i am targeting android and iOS.
I am using Xamarin.Forms.Editor for reply
Editor _replyEntry = new Editor
{
HorizontalOptions = LayoutOptions.FillAndExpand,
TextColor = Color.Black
}
in this case the editor height remains constant and allows scrolling and editor does not expands
Then i used InvalidateMeasure()
_replyEntry .TextChanged += (sender, e) => { this.InvalidateMeasure(); };
in this case editor expands as when the text requires more space but does not allow scroll inside editor and if user types long message then editor does not allows scroll and text goes behind the keyboard and not visible to user
Is there any way to enable scroll and give max height to edit either in xamarin.forms of by writing custom renderer
Thanks
Here is my code
public class abc : ContentPage
{
public abc()
{
Image attchment = new Image
{
Source = "attachment.png",
HorizontalOptions = LayoutOptions.Start
};
Editor _replyEntry = new Editor
{
HorizontalOptions = LayoutOptions.FillAndExpand,
TextColor = Color.Black,
};
Button _sendButton = new Button
{
Text = "Send",
TextColor = Color.Black,
BackgroundColor = Color.Transparent,
HorizontalOptions = LayoutOptions.End
};
StackLayout replyStack = new StackLayout
{
Orientation = StackOrientation.Horizontal,
Padding = new Thickness(10),
Spacing = 10,
VerticalOptions = LayoutOptions.End,
Children = { attchment, _replyEntry, _sendButton }
};
Content = replyStack;
}
}
It looks like you will have to use a custom renderer to achieve what you are wanting.
There is a post here that has pretty much the same thing with what you are trying to achieve for Android.
In that demo it has an expanding multi-line EditText control (android:singleLine="false"), with only vertical scrollbars (android:scrollbars="vertical"), whilst disabling the horizontal scrollbars (android:scrollHorizontally="false").
You need to ensure the Editor' parent is expanding, then the editor will automatically expand too. If you make an empty contentpage and add an Editor, the is will just expand. If you place it inside a stacklayout, the you need to ensure that the stacklayout is expanding.

Adding space in Xamarin.Forms layouts?

What's the proposed way to add space to layouts in Xamarin.Forms?
One way would be to add a Frame with no children like so:
new Frame {
BackgroundColor = Color.White,
HeightRequest = 1,
MinimumHeightRequest = 1,
HasShadow = false
}
Unfortunately, HeightRequest and MinimumHeightRequest get ignored.
Does a better way exist?
You could put your controls inside layouts (like frame, scroll view, stack panel) and use Padding property:
this.stackPanel = new StackLayout ()
{
Padding = new Thickness (8, 8)
};
var scrollView = new ScrollView ()
{
Content = stackPanel,
Padding = new Thickness (1, 2, 3, 4)
};
var frame = new Frame ()
{
Padding = new Thickness (8)
};
If you want space between two buttons for example, I believe this would do the trick. The first one adds 10 to bottom padding, the second adds 10 to top padding for total of 20.
var frame1 = new Frame ()
{
Padding = new Thickness (0,0,0,10),
Content = new Button()
};
var frame2 = new Frame ()
{
Padding = new Thickness (0,10,0,0),
Content = new Button()
};
Most Xamarin.Forms Layouts supports adding space between elements:
StackLayout has a Spacing property,
Grid has RowSpacing and ColumnSpacing properties,
...
Now, if you want to add spacing at a particular place, the way to to it is to include a BoxView:
myStackLayout.Children.Add (new BoxView {Color = Color.Transparent, HeightRequest = 5});
You can also wrap your content in a Frame or ContentView, but it adds padding to the content instead of adding space (although the effect will be the same).
What I do worked perfectly for me:
Suppose you want to distribute 2 Labels evenly on a horizontal StackLayout:
new StackLayout
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions=LayoutOptions.CenterAndExpand,
Spacing = 0, // <- Very important!!
Children = {
new Label { Text = "Label 1" },
new BoxView { HorizontalOptions = LayoutOptions.FillAndExpand }, // <- the clever part
new Label { Text = "Label 2" }
}
};
Summary
By inserting BoxViews that fill the remaining space ("FillAndExpand") between your views, your views appear evenly distributed.
By setting Spacing = 0, you don't get extra space between your views.
Try:
myFrame.TranslateX=10;
myFrame.TranslateY=10;
I wanted to share a screenshot in conjunction with Lay González's answer but the edit queue was full->
To get dynamic spacing similar to CSS "Space-Between" in Xamarin you can insert filler views between your views that actually have content.
Here is an example:
Omit the filler view after the last "actual" view so that the view you want is at the end (the "-50" label at the bottom in the example).

Resources