How to set auto fill to grid column width - xamarin

I have a grid with only one row with the height of GridLength.Star.
In the first column I have an svg that fills the cell.
In the second column I have a label.
The svg is a square and should take the place to fill it in vertical and horizontal direction but not more.
The label should take the rest of the width.
I tried to set
column1.Width = GridLength.Auto;
column2.Width = GridLength.Star;
but it will always be devided in the middle.
So I got:
svg..........|label........
instead of (what I want):
svg|label..................
Any ideas?
UPDATE
Label label = new Label();
SvgCachedImage svgImage = new SvgCachedImage();
svgImage.HorizontalOptions = LayoutOptions.CenterAndExpand;
svgImage.VerticalOptions = LayoutOptions.CenterAndExpand;
Grid grid = new Grid();
grid.Children.Add( svgImage );
grid.Children.Add( label );
RowDefinition row = new RowDefinition();
ColumnDefinition column1 = new ColumnDefinition();
ColumnDefinition column2 = new ColumnDefinition();
row.Height = GridLength.Star;
grid.RowDefinitions = new RowDefinitionCollection { row1 };
column1.Width = GridLength.Auto;
column2.Width = GridLength.Star;
grid.ColumnDefinitions = new ColumnDefinitionCollection { column1, column2 };
UPDATE 2
Sorry it is no Fill but a CenterAndExpand

I got the answer. I simply need to set the height of the svg to its widthRequest:
svgImage.WidthRequest = svgImage.Height;
column1.Width = GridLength.Auto;
column2.Width = GridLength.Star;
grid.Children.Add( svgImage, 0, 0 );
grid.Children.Add( label, 1, 0 );

Well, its very simple actually the reason behind it is the GridLength.Auto you have there all you need to do is change the Grid column definitions into something like this:
XAML
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/> // svg
<ColumnDefinition Width="4*"/> // label
</Grid.CoulmnDefinitions>
C#
Grid grid= new Grid
{
ColumnDefinitions =
{
new RowDefinition { Height = new GridLength(1, GridUnitType.Star) },
new RowDefinition { Height = new GridLength(4, GridUnitType.Star) },
}
}
grid.Children.Add(svgImage, 0, 0);
grid.Children.Add(label, 0, 1);

Move:
grid.Children.Add( svgImage );
grid.Children.Add( label );
to after you've set up your row/column definitions, and then change to:
grid.Children.Add(svgImage, 0, 0);
grid.Children.Add(label, 0, 1);
You basically have to tell the grid which row/column to put your elements. By adding them to the grid before initialising the column definitions, the ColumnDefinitions have defaulted to GridLength.Star.
I've tidied up your code. Note that I have changed the Height assignments.
Label label = new Label()
{
Text = "Some text" // Just some placeholder text
};
SvgCachedImage svgImage = new SvgCachedImage()
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand
};
Grid grid = new Grid();
// NOTE: use GridLength class to set the Height/Width of rows/columns
RowDefinition row = new RowDefinition()
{
Height = new GridLength(1, GridUnitType.Star)
}
ColumnDefinition column1 = new ColumnDefinition()
{
Width = new GridLength(1, GridUnitType.Auto)
}
ColumnDefinition column2 = new ColumnDefinition()
{
Width = new GridLength(1, GridUnitType.Star)
}
// Use existing instances of the definitions
grid.RowDefinitions.Add(row1);
grid.ColumnDefinitions.Add(column1);
grid.ColumnDefinitions.Add(column2);
grid.Children.Add(svgImage, 0, 0);
grid.Children.Add(label, 1, 0);
As I was typing this out I noticed that you had simply set the Width property to GridLength.Star/Auto. According to the docs, you should be using the GridLength class, not the Enum.

Related

Xamarin.Forms: Relative Layout inside Grid layout not working properly

I want to create dynamic grid layout with one row with 2 column and another row with only one column with colspan 2.
And every column may contain on overlay image at top right corner.
For this i tried to add relative layout in grid layout but the issue is image tag in relative layout is not occupying complete width.
code to create relative layout
for (int i = 0; i < temp.Count; i++)
{
var data = temp[i];
var framelyt = new Frame { CornerRadius = 4, IsClippedToBounds = true, HasShadow = false, Padding = 0, HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand };
Image imageStack = new Image { Source = "placeholder_image1", Margin = 0, Aspect = Aspect.Fill, HorizontalOptions = LayoutOptions.FillAndExpand };
Image cmpltimageStack = new Image { Source = "completed_icon", Aspect = Aspect.Fill, HeightRequest = 32, IsVisible=true };
RelativeLayout relativeLayout = new RelativeLayout { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand, BackgroundColor = Color.Beige };
framelyt.Content = imageStack;
relativeLayout.Children.Add(framelyt, Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}), Constraint.Constant(0)); relativeLayout.Children.Add(cmpltimageStack,
Constraint.RelativeToParent((parent) =>
{
return parent.Width - 50;
}),
Constraint.Constant(0));
gridStckActivity.Children.Add(relativeLayout, column, row);
if (column == 1)
{
column = 0;
isSingle = true;
row++;
}
else
{
column = 1;
}}
It was working on android device properly but on iOS it was leaving some space on right padding. After adding x,y and width constraint it worked properly on both device.
Here is the revised code.
for (int i = 0; i < temp.Count; i++)
{
var data = temp[i];
var framelyt = new Frame { CornerRadius = 4, IsClippedToBounds = true, HasShadow = false, Padding = 0, HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand };
Image imageStack = new Image { Source = "placeholder_image1", Margin = 0, Aspect = Aspect.Fill, HorizontalOptions = LayoutOptions.FillAndExpand };
Image cmpltimageStack = new Image { Source = "completed_icon", Aspect = Aspect.Fill, HeightRequest = 32, IsVisible=true };
RelativeLayout relativeLayout = new RelativeLayout { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand, BackgroundColor = Color.Beige };
framelyt.Content = imageStack;
relativeLayout.Children.Add(framelyt, Constraint.Constant(0), Constraint.Constant(0),Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}));
relativeLayout.Children.Add(cmpltimageStack,
Constraint.RelativeToParent((parent) =>
{
return parent.Width - 50;
}),
Constraint.Constant(0));
gridStckActivity.Children.Add(relativeLayout, column, row);
if (column == 1)
{
column = 0;
isSingle = true;
row++;
}
else
{
column = 1;
} }

Setting relative height for Grid children

I'm adding 2 children to a Grid like this:
private void pInitStackLayout()
{
grid1 = new Grid()
{
};
grid2 = new Grid()
{
};
biggrid = new Grid()
{
BackgroundColor = Color.Transparent,
Margin = new Thickness(0),
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.StartAndExpand,
Orientation = StackOrientation.Vertical,
};
biggrid.Children.Add(grid1,0,0);
biggrid.Children.Add(grid2,0,1);
this.Content = biggrid;
}
The ContentPage's (which is a Navigation Page) Content is the biggrid.
I would like to make it so that grid1 takes up 80% of the available height, and grid2 takes up 20% (or the rest).
How could I achieve this?
It's very simple actually, just set the RowDefinitions of biggrid.
// RowDefinitions isolated
RowDefinitions = new RowDefinitionCollection
{
new RowDefinition { Height = new GridLength(8, GridUnitType.Star) },
new RowDefinition { Height = new GridLength(2, GridUnitType.Star) }
}
// RowDefinitions isolated
// Actual code
private void pInitStackLayout()
{
grid1 = new Grid()
{
};
grid2 = new Grid()
{
};
biggrid = new Grid()
{
RowDefinitions = new RowDefinitionCollection
{
new RowDefinition { Height = new GridLength(8, GridUnitType.Star) },
new RowDefinition { Height = new GridLength(2, GridUnitType.Star) }
},
BackgroundColor = Color.Transparent,
Margin = new Thickness(0),
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.StartAndExpand,
Orientation = StackOrientation.Vertical,
};
biggrid.Children.Add(grid1,0,0);
biggrid.Children.Add(grid2,0,1);
this.Content = biggrid;
}

How to make sure elements land on full pixel boundaries in a StackLayout?

I have a StackLayout holding some elements for a custom cell in a ListView. The problem I am running in to is that my images are not landing on full pixel boundaries. This is causing the straight lines in my graphics to become blurry as they are not landing on pixel boundaries. Is there a way for me to easily prevent this behavior, perhaps in a custom renderer?
public InputEditCell()
{
image = new Image { HorizontalOptions = LayoutOptions.Start };
image.SetBinding(Image.SourceProperty, new Binding("Image.ImageNameSelect"));
image.BindingContext = _tempInputViewModel;
var tappedImageGesture = new TapGestureRecognizer
{
Command = new Command(OnImageTapped),
CommandParameter = image
};
image.GestureRecognizers.Add(tappedImageGesture);
nameEntry = new Entry()
{
TextColor = Color.FromHex("E60006"),
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Entry)),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.FillAndExpand
};
nameEntry.SetBinding(Entry.TextProperty, "Name");
nameEntry.BindingContext = _tempInputViewModel;
var acceptImage = new Image
{
Source = ResourceHandler.GetAcceptImage(),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.End,
};
var tappedAcceptGesture = new TapGestureRecognizer
{
Command = new Command(OnAcceptTapped),
CommandParameter = acceptImage
};
acceptImage.GestureRecognizers.Add(tappedAcceptGesture);
var cancelImage = new Image
{
Source = ResourceHandler.GetCancelImage(),
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.End,
};
var tappedCancelGesture = new TapGestureRecognizer
{
Command = new Command(OnCancelTapped),
CommandParameter = cancelImage
};
cancelImage.GestureRecognizers.Add(tappedCancelGesture);
var viewLayout = new StackLayout {
Orientation = StackOrientation.Horizontal,
Children = { image, nameEntry, acceptImage, cancelImage },
Padding = new Thickness(10, 10, 10 ,10)
};
View = viewLayout;
View.GestureRecognizers.Clear();
View.GestureRecognizers.Add(new TapGestureRecognizer());
}

ViewCell - image fill, text on bottom

The layout i want is like this: http://imgur.com/etb9ZKZ
I want the image (illustrated with the color green) to fill the entire layoutcontol. On top of image positioned at the bottom with full width i want a textbox/label to put a title. The title view should have a black semi-transparent background.
This is the best i've got (the code below), but it has a few issues:
#1 - The text doesnt wrap like it is suppose to. It just cuts the sentence, like the rest is going off screen.
#2 - The image doesnt scale to the width of the container.
Label lblTitle = new Label()
{
BackgroundColor = new Color(0, 0, 0, 0.8),
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
};
lblTitle.SetBinding(Label.TextProperty, "headline");
Image imgBanner = new Image()
{
/*
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.End,
Aspect = Aspect.Fill
*/
};
imgBanner.SetBinding(Image.SourceProperty, "ImageUrlSource");
AbsoluteLayout.SetLayoutFlags(lblTitle, AbsoluteLayoutFlags.PositionProportional | AbsoluteLayoutFlags.WidthProportional);
AbsoluteLayout.SetLayoutBounds(lblTitle, new Rectangle(0, 1, 1, AbsoluteLayout.AutoSize));
AbsoluteLayout.SetLayoutFlags(imgBanner, AbsoluteLayoutFlags.SizeProportional);
AbsoluteLayout.SetLayoutBounds(imgBanner, new Rectangle(0, 0, 1, 1));
AbsoluteLayout layout = new AbsoluteLayout()
{
HorizontalOptions = LayoutOptions.Fill,
Children =
{
imgBanner,
lblTitle
}
};
View = layout;
You should use Grid instead.
Label lblTitle = new Label()
{
BackgroundColor = new Color(0, 0, 0, 0.8),
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
};
lblTitle.SetBinding(Label.TextProperty, "headline");
Image imgBanner = new Image()
{
/*
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.End,
Aspect = Aspect.Fill
*/
};
imgBanner.SetBinding(Image.SourceProperty, "ImageUrlSource");
//=========== Addition Start Here ============//
Grid grid = new Grid();
grid.RowDefinitions =
{
new RowDefinition{ Height=new GridLength(200,GridUnitType.Absolute) },
new RowDefinition{ Height=new GridLength(30,GridUnitType.Absolute},
}
grid.Children.Add(imgBanner,0,1,0,2); //two rowspan
// == .Add(imgBanner,column,column+columnspan,row,row+rowspan)
grid.Children.Add(lblTitle,0,1,1,2); //one rowspan
View = grid;

How to center a view horizontally in a Xamarin.Forms RelativeLayout?

I want to center a label horizontally in a RelativeLayout in Xamarin.Forms. I tried something like this, but it doesn't work:
var label = new Label {HorizontalOptions = LayoutOptions.Center};
var rl = new RelativeLayout();
rl.Children.Add(label, Constraint.RelativeToParent((parent) => parent.Width / 2 - label.Width / 2));
I want to place a second label on the right of my label while the first label is centered horizontally. How can I achieve that?
When you are doing RelativeLayouts you have Constraints that you can specify.
To achieve what you are aiming to do, you need to use a RelativeToParent Constraint first, and then a RelativeToView Constraint for the 2nd label that is attached to the right of the first view.
The first view will then be centered horizontally across the whole page, with the 2nd label attached relative to the first view afterwards.
The following example shows this:-
RelativeLayout objRelativeLayout = new RelativeLayout();
Label objLabel1 = new Label();
objLabel1.BackgroundColor = Color.Red;
objLabel1.Text = "This is a label";
objLabel1.WidthRequest = 300;
objRelativeLayout.Children.Add(objLabel1,
xConstraint: Constraint.RelativeToParent((parent) =>
{
return ((parent.Width - objLabel1.Width) / 2);
}));
Label objLabel2 = new Label();
objLabel2.BackgroundColor = Color.Blue;
objLabel2.Text = "Hi";
objLabel2.WidthRequest = 100;
objRelativeLayout.Children.Add(objLabel2,
xConstraint: Constraint.RelativeToView(objLabel1,
new Func<RelativeLayout, View, double>((pobjRelativeLayout, pobjView) =>
{
return pobjView.X + pobjView.Width;
})));
this.Content = objRelativeLayout;
Update 1:-
If you don't want to use a specified Width or the contents are of an unknown size then you will have to trigger a re-layout via calling ForceLayout on the RelativeLayout when the view(s) need to be repositioned according to the Constraints you have defined.
The updated example below illustrates this:-
StackLayout objStackLayout = new StackLayout()
{
Orientation = StackOrientation.Vertical,
};
RelativeLayout objRelativeLayout = new RelativeLayout();
objStackLayout.Children.Add(objRelativeLayout);
Label objLabel1 = new Label();
objLabel1.BackgroundColor = Color.Red;
objLabel1.Text = "This is a label";
objLabel1.SizeChanged += ((o2, e2) =>
{
objRelativeLayout.ForceLayout();
});
objRelativeLayout.Children.Add(objLabel1,
xConstraint: Constraint.RelativeToParent((parent) =>
{
return ((parent.Width - objLabel1.Width) / 2);
}));
Label objLabel2 = new Label();
objLabel2.BackgroundColor = Color.Blue;
objLabel2.Text = "Hi";
objRelativeLayout.Children.Add(objLabel2,
xConstraint: Constraint.RelativeToView(objLabel1,
new Func<RelativeLayout, View, double>((pobjRelativeLayout, pobjView) =>
{
return pobjView.X + pobjView.Width;
})));
Button objButton1 = new Button();
objButton1.Text = "Test1";
objButton1.Clicked += ((o2, e2) =>
{
objLabel1.Text = "This is some other label text";
});
objStackLayout.Children.Add(objButton1);
this.Content = objStackLayout;

Resources