I am trying to make a gallery style grid view in Xamarin forms for iOS and Android but have an issue where layout options seem to be ignored and I get different results for iOS and Android.
Basic layout is:
frame with a border(red) containing a stack layout (pink) set to FillAndExpand for both horizontal and vertical options which contains a label at the top and an image below set to fill the rest of the stack.
The image seems to just expand outside of the stack and the frame and ignore the vertical options set.
I have tried setting these vertical options to Fill, FillAndExpand, CentreAndExpand but all have the same result.
If i remove the Stack layout and label and have the image as the only child element in the frame then it works as expected but I am required to also show a label.
The result is the same in landscape and portrait orientations.
Results on platform with iOS being the main issue here:
Code for adding an image to the grid:
var imageSource = ImageSource.FromStream(() => new MemoryStream(imageData));
var framedImage = new Frame
{
Padding = 0,
Margin = 3,
GestureRecognizers = { tapGesture },
Content = new StackLayout
{
Padding = 10,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.Pink,
Children =
{
textLabel,
new Image
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Source = imageSource,
Aspect = Aspect.AspectFit
},
}
},
BackgroundColor = StyleSheet.BackgroundColorLight,
BorderColor = StyleSheet.OutlineColorDark,
CornerRadius = 5,
HasShadow = false
};
grid.Children.Add(framedImage, columnCounter, rowCounter);
Thanks in advance!
Fixed it by doing this:
var image = new Image
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Source = imageSource,
Aspect = Aspect.AspectFit
};
var framedImage = new Frame
{
Padding = 2,
Margin = 1,
GestureRecognizers = { tapGesture },
Content = image,
HasShadow = false,
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
var innergrid = new Grid
{
RowDefinitions =
{
new RowDefinition {Height = new GridLength(20, GridUnitType.Auto)},
new RowDefinition {Height = new GridLength(20, GridUnitType.Star)},
}
};
innergrid.Children.Add(textLabel, 0, 0);
innergrid.Children.Add(framedImage, 0, 1);
var frame = new Frame
{
Padding = 5,
Margin = 3,
GestureRecognizers = { tapGesture },
Content = innergrid,
BackgroundColor = StyleSheet.BackgroundColorLight,
BorderColor = StyleSheet.OutlineColorDark,
CornerRadius = 5,
HasShadow = true
};
grid.Children.Add(frame, columnCounter, rowCounter);
I might have a go with the new FlexLayout to see if i can have simpler code
Related
I have made side menu using Rg.Plugins.Popups for Xamarin.
Everything is ok, but appearing animation doesn't work for some reason. As you can see menu just appears out of nowhere when it should look like disappearing animation.
FilterMenuCommand = new Command(() =>
{
var contentView = new ReportsPageFilterMenuContentView(this);
PopupNavigation.Instance.PushAsync(new ReportsPageFilterMenuPopupPage(contentView, this));
});
My PopupPage class:
public partial class ReportsPageFilterMenuPopupPage : PopupPage
{
public ReportsPageFilterMenuPopupPage(ReportsPageFilterMenuContentView contentView, ReportsViewModel viewModel)
{
InitializePageComponent(contentView, viewModel);
}
protected void InitializePageComponent(ReportsPageFilterMenuContentView contentView, ReportsViewModel viewModel, float width = 340.0f)
{
BindingContext = viewModel;
var moveAnimation = new MoveAnimation
{
DurationIn = 800,
DurationOut = 600,
EasingIn = Easing.SinIn,
EasingOut = Easing.SinOut,
HasBackgroundAnimation = true,
PositionIn = MoveAnimationOptions.Right,
PositionOut = MoveAnimationOptions.Right,
};
Animation = moveAnimation;
Resources["DecimalConverter"] = new DecimalConverter();
var frame = new Frame
{
WidthRequest = width,
CornerRadius = 0,
Padding = new Thickness(24, 20, 24, 20),
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.StartAndExpand,
BackgroundColor = Color.White
};
var gridRowDefinitions = new RowDefinitionCollection
{
new RowDefinition {Height = GridLength.Auto}, new RowDefinition {Height = GridLength.Star}
};
var grid = new Grid
{
RowDefinitions = gridRowDefinitions
};
var stackLayout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
BackgroundColor = Color.White
};
Grid.SetRow(stackLayout, 0);
Grid.SetRow(contentView, 1);
var label = new Label
{
FontFamily = "Roboto",
FontAttributes = FontAttributes.Bold,
FontSize = 20,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Start,
Margin = new Thickness(1),
Text = MainResource.Filters
};
var imageButton = new ImageButton
{
Source = (FileImageSource)#"Assets/cross.png",
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.EndAndExpand,
Margin = new Thickness(1),
Command = viewModel.CloseCommand
};
stackLayout.Children.Add(label);
stackLayout.Children.Add(imageButton);
grid.Children.Add(stackLayout);
grid.Children.Add(contentView);
frame.Content = grid;
Content = frame;
}
}
Xamarin.Forms version: 4.6.0.800
Rg.Plugins.Popup version: 2.0.0.3
If you have any clue or idea where to even start fixing this problem, please, share it with me in comments.
I use your code and test on the following simulators
Android phone
Android tablet
iOS iPhone
iOS iPad
It works fine , the appearing and disappearing animation works as expected .
I would suggest you update Xamarin.Forms and Rg.Plugins.Popup version package to the latest .
Here is my code:
List<Entry> entries = new List<Entry>
{
new Entry(7)
{
Color = SKColor.Parse("#166DA3"),
},
new Entry(3)
{
Color = SKColors.Transparent,
}
};
public RoundScore2()
{
Content = _contentLayout; // layout inherited from a different class
Label congrats = new Label
{
Text = "Congratulations!",
FontAttributes = FontAttributes.Bold,
FontSize = 30,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.Start,
TextColor = Color.Black
};
_contentStack.Children.Add(congrats); // _contentStack inherited from same class, _contentStack is added to _contentLayout
ChartView Chart1 = new ChartView
{
VerticalOptions = LayoutOptions.CenterAndExpand,
HeightRequest = 80
};
_contentStack.Children.Add(Chart1);
Chart1.Chart = new DonutChart() { Entries = entries, HoleRadius = 5 };
Button nextRound = new Button
{
Text = "Start Round " + roundCounter.ToString(),
Margin = new Thickness(10, 20, 10, 10),
TextColor = Color.Black,
BackgroundColor = Color.FromHex("48AADF"),
FontFamily = "Source Sans Pro",
FontSize = 20,
FontAttributes = FontAttributes.Bold,
CornerRadius = 8,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.StartAndExpand,
WidthRequest = 180
};
_contentStack.Children.Add(nextRound);
}
Stack overflow is not letting me add the photo right now ("Failed to upload image; couldn't reach imgur")...but basically, I can only see the horizontal middle section of the pie chart. There is enough space for the chart to show, but it is just cut off. I have tried setting VerticalOptions = LayoutOptions.FillAndExpand along with LayoutOptions.CenterAndExpand and no luck. Does anyone know why this is happening?
Edit: even with the Label and Button taken out, the view is still cut off.
but basically, I can only see the horizontal middle section of the pie chart.
From shared code of ChartView, I'm guessing that whether the width of chart view is too small.
ChartView Chart1 = new ChartView
{
VerticalOptions = LayoutOptions.CenterAndExpand,
HeightRequest = 80
};
If so , you can add HorizontalOptions as follow:
ChartView Chart1 = new ChartView
{
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 80
};
In addition , also can add HorizontalOptions for StackLayout:
_contentStack.HorizontalOptions = LayoutOptions.FillAndExpand;
_contentStack.VerticalOptions = LayoutOptions.FillAndExpand;
It worked after changing VerticalOptions = LayoutOptions.Center and HorizontalOptions = LayoutOptions.Fill as well as changing HoleRadius = .5f.
I am currently using the package ZXing.Net.Mobile for Xamarin Forms.
I want content on the top of the screen and at the bottom of the screen and I want the scanner to be somewhere in the middle.
If I specify the height of the scanner, it stretches it making it ugly and not nice to have (because the scanner is meant to be used for full screen?).
I want to have some content on the top of the screen with a dynamic height, then I want the scanner with height 150-200, then I want some content to be shown on the rest of the screen.
I was looking into ZXingDefaultOverlay but I could not get it to work as I wanted.
Anyone has an idea, example or an answer that can help me?
Following is the sample code where I have used Grid
for showing content on top and bottom of the screen and middle screen contains scanner.
public ZXingDefaultOverlay()
{
BindingContext = this;
RowSpacing = 0;
VerticalOptions = LayoutOptions.FillAndExpand;
HorizontalOptions = LayoutOptions.FillAndExpand;
RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
RowDefinitions.Add(new RowDefinition { Height = new GridLength(2, GridUnitType.Star) });
RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
Children.Add(new BoxView
{
VerticalOptions = LayoutOptions.Fill,
HorizontalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.Transparent,
Opacity = 0.7,
}, 0, 0);
Children.Add(new BoxView
{
VerticalOptions = LayoutOptions.Fill,
HorizontalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.Transparent,
Opacity = 0.7,
}, 0, 2);
StackLayout ImageLabelContainer = new StackLayout();
Image imgBox = new Image();
imgBox.Source = "scan_qr.png";
imgBox.VerticalOptions = LayoutOptions.Fill;
imgBox.HorizontalOptions = LayoutOptions.FillAndExpand;
ImageLabelContainer.Children.Add(imgBox);
Label lblSuccess = new Label();
lblSuccess.Margin = new Thickness(0, 7, 0, 0);
lblSuccess.HorizontalTextAlignment = TextAlignment.Center;
lblSuccess.TextColor = Color.Green;
lblSuccess.AutomationId = "zxingDefaultOverlay_BottomTextLabel";
lblSuccess.SetBinding(Label.TextProperty, new Binding(nameof(BottomText)));
ImageLabelContainer.Children.Add(lblSuccess);
Children.Add(ImageLabelContainer, 0, 1);
}
Here you can set height of the rows as per your requirement.
I have something like this so far for my view:
public StackLayout OffersSlideViewCarouselChild(Offer offer)
{
Image productImage = new Image
{
Source = ImageSource.FromUri(new Uri(offer.Image.Replace("https://", "http://"))),
HeightRequest = 270,
WidthRequest = 270,
Aspect = Aspect.AspectFit
};
var topStackLayout = new StackLayout
{
Spacing = 0
};
topStackLayout.Children.Add(productImage);
StackLayout contentStackLayout = new StackLayout
{
Spacing = 0,
Padding = new Thickness(5, 10, 5, 10),
Orientation = StackOrientation.Vertical
};
var savedBtn = SavedButtonLayout(offer.IsSelected, offer.Id);
var redeemBtn = RedeemBtnLayout(offer.Id);
var timeRemainingLabel = TimeRemainingLayout(offer, offer.Id);
contentStackLayout.Children.Add(new UILabel(16) {
Text = offer.ProductName,
TextColor = ColorHelper.FromHex(CoreTheme.COLOR_OFFERCELL_PRODUCT_TEXT),
FontFamily = CoreTheme.FONT_FAMILY_DEFAULT_BOLD,
WidthRequest = DeviceDisplaySettings.defaultwidth,
VerticalTextAlignment = TextAlignment.Center
});
contentStackLayout.Children.Add(new UILabel(14)
{
Text = offer.Headline,
TextColor = ColorHelper.FromHex(CoreTheme.COLOR_OFFERCELL_PRODUCT_TEXT),
FontFamily = CoreTheme.FONT_FAMILY_DEFAULT_BOLD,
WidthRequest = DeviceDisplaySettings.defaultwidth,
VerticalTextAlignment = TextAlignment.Center
});
contentStackLayout.Children.Add(new UILabel(14) {
Text = offer.LongRewardsMessage,
TextColor = ColorHelper.FromHex(CoreTheme.COLOR_DEAL_PAGE_LONG_REWARD_MESSAGE_RED),
FontFamily = CoreTheme.FONT_FAMILY_DEFAULT_BOLD,
WidthRequest = DeviceDisplaySettings.defaultwidth,
VerticalTextAlignment = TextAlignment.Center
});
if (!string.IsNullOrEmpty(offer.PowerMessage)) {
var htmlText = string.Format("<html><body style='color:#9b9b9b'>{0}</body></html>", offer.PowerMessage.Replace(#"\", string.Empty));
var browser = new WebView() {
//HeightRequest = (DeviceDisplaySettings.defaultheight > 600) ? 500 : 400,
HeightRequest = 800,
Source = new HtmlWebViewSource() { Html = htmlText },
};
browser.Navigating += OnNavigating;
contentStackLayout.Children.Add(browser);
}
var nestedStackLayout = new StackLayout()
{
VerticalOptions = LayoutOptions.FillAndExpand
};
nestedStackLayout.Children.Add(topStackLayout);
nestedStackLayout.Children.Add(timeRemainingLabel);
nestedStackLayout.Children.Add(contentStackLayout);
var mainScrollView = new ScrollView()
{
Padding = new Thickness(0, 0, 0, 10),
VerticalOptions = LayoutOptions.FillAndExpand,
Orientation = ScrollOrientation.Vertical,
Content = nestedStackLayout
};
var mainStackLayout = new StackLayout()
{
Spacing = 5,
Padding = new Thickness(0, 0, 0, 0),
VerticalOptions = LayoutOptions.Fill,
HorizontalOptions = LayoutOptions.Fill,
Orientation = StackOrientation.Vertical,
Children = { savedBtn, mainScrollView, redeemBtn }
};
return mainStackLayout;
}
private StackLayout SavedButtonLayout(bool isSelected, int offerid)
{
int buttonsToShow = 2;
bool displaySaveButton = true;
if (IsPremisesOffer (offerid)) {
buttonsToShow = 3;
displaySaveButton = false;
}
btnShare = new UIFieldDefinition(_pageFieldDefinition.ShareButtonDefinition);
btnShare.Text = "SHARE";
btnShare.ClassId = offerid.ToString();
btnShare.WidthRequest = (DeviceDisplaySettings.defaultwidth / buttonsToShow) - 40;
btnShare.BackgroundColor = Color.FromRgb(167, 188, 33);
btnShare.VerticalContentAlignment = TextAlignment.Center;
btnShare.HandleClick(btnShare_Clicked);
btnSave = new UIFieldDefinition(_pageFieldDefinition.SaveButtonDefinition);
btnSave.Text = isSelected ? "UNSAVE" : "SAVE";
btnSave.ClassId = offerid.ToString();
btnSave.WidthRequest = (DeviceDisplaySettings.defaultwidth / buttonsToShow) - 40;
btnSave.BackgroundColor = Color.FromRgb(167, 188, 33);
btnSave.VerticalContentAlignment = TextAlignment.Center;
btnSave.HandleClick(btnSave_Clicked);
rl = new StackLayout {
Spacing = 10,
Orientation = StackOrientation.Horizontal,
BackgroundColor = Color.FromRgb(196, 221, 57),
Padding = new Thickness(40, 5, 5, 5),
WidthRequest = DeviceDisplaySettings.defaultwidth
};
rl.Children.Add(btnShare);
if (displaySaveButton) rl.Children.Add(btnSave);
return rl;
}
public UIFieldDefinition RedeemBtnLayout(int offerid)
{
int buttonsToShow = 1;
btnRedeem = new UIFieldDefinition(_pageFieldDefinition.RedeemButtonDefinition);
btnRedeem.Text = "REDEEM NOW";
btnRedeem.ClassId = offerid.ToString();
btnRedeem.WidthRequest = (DeviceDisplaySettings.defaultwidth / buttonsToShow) - 10;
// btnRedeem.HorizontalOptions = LayoutOptions.FillAndExpand;
// btnRedeem.VerticalOptions = LayoutOptions.EndAndExpand;
btnRedeem.HandleClick(btnRedeem_Clicked);
return btnRedeem;
}
However, I am noticing that the Redeem button does not even display on the view (It's supposed to be fixed on the bottom).
The scrollview works but the buttom is missing. Why?
Please let me know if you need further code details.
Moving here from comments above. There are two separate issues from what I can tell, and as far as I can tell, are unrelated:
The WebView, nested inside the ScrollView, is not big enough to fully display the content.
The button that is supposed to be at the bottom of the screen is not displaying.
For both of them, the answer is probably in how you are setting HeightRequest. There have been a lot of suggestions by myself and other commenters to change or get rid of some of the HeightRequest settings, and I'm not sure of the current state of your source code. So assuming those are still there:
For solving the WebView issue, read How can I add HTML to a Stacklayout inside a Scrollview in Xamarin forms?. This will let you figure out the right HeightRequest to use. The short answer is that depending on exactly what you want to happen, you may need a custom renderer. Note that the HeightRequest for the WebView will not affect any layout outside of the ScrollView.
For solving the issue of the button not appearing, get rid of the HeightRequest setting on the ScrollView, and the VerticalOptions on the StackLayout created in SavedButtonLayout.
I am assuming you did the experiment suggested above to make sure that the redeemBtn will render if placed before the ScrollView, and it does show up then. If not, you first need to fix that.
If you have "fixed" this by changing the HeightRequest then your real problem is the fixed pixel size of all your views and layouts, I recommend you DON'T use fixed pixel sizes for different screen resolution this will be a bigger problem later, What you can do is get the Screen size and do the math to fit all your elements of the view, one way to get the width and height of the screen is on the OnSizeChanged event of Pages (Like ContentPage), something like this:
SizeChanged += SizeChanged;
void SizeChanged (object sender, EventArgs e)
{
Layout.WidthRequest = Width * 0.3;
Layout.HeightRequest = Height * 0.35;
}
Your layout is pretty busy. A few things:
Set VerticalOptions to EndAndExpand for redeemBtn.
Set VerticalOptions to StartAndExpand for savedBtn.
Set VerticalOptions to Fill for mainScrollView.
Set VerticalOptions to FillAndExpand for mainRelLayout.
Set VerticalOptions and HorizontalOptions to Fill for
mainStackLayout.
I think that will get you to where you want to be.
The options that include "Expand" will grow the element to accommodate the desired height of its contents.
Here is my issue:
The red block is meant to be the avatar for the person sometime, and the blue balloon a chat message. The chat message object is a RelativeLayout with a Label and an Image positioned one of top of each other, but not matter what I do, I can't get it to be centered. I only have one View:
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace TestChat
{
public partial class ChatPage : ContentPage
{
public ChatPage ()
{
this.Title = "Chat page";
InitializeComponent ();
}
void OnChatClick (object sender, EventArgs args) {
Image pic = new Image {
Source = "bubble.png",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Aspect = Aspect.Fill
};
Label textLabel = new Label {
Text = "Hello",
TextColor = Color.White,
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.EndAndExpand
};
Frame picFrame = new Frame {
HasShadow = false,
BackgroundColor = Color.Red,
Padding = new Thickness (0),
Content = pic
};
Frame textFrame = new Frame {
HasShadow = false,
BackgroundColor = Color.Transparent,
Padding = new Thickness (0,0,15,0),
Content = textLabel
};
RelativeLayout overlayLayout = new RelativeLayout { BackgroundColor = Color.Blue, HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand };
overlayLayout.Children.Add (picFrame,
xConstraint: Constraint.RelativeToParent((parent) => parent.X),
yConstraint: Constraint.RelativeToParent((parent) => parent.Y),
widthConstraint: Constraint.RelativeToParent((parent) => parent.Width-2),
heightConstraint: Constraint.RelativeToParent((parent) => parent.Height-2)
);
overlayLayout.Children.Add (textFrame,
xConstraint: Constraint.RelativeToParent((parent) => parent.X),
yConstraint: Constraint.RelativeToParent((parent) => parent.Y),
widthConstraint: Constraint.RelativeToParent((parent) => parent.Width-2),
heightConstraint: Constraint.RelativeToParent((parent) => parent.Height-2)
);
Frame overlayContainerFrame = new Frame {
HasShadow = false,
BackgroundColor = Color.Red,
Padding = new Thickness(1),
HeightRequest = 100,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Content = overlayLayout
};
StackLayout horizontalLayout = new StackLayout {
Orientation = StackOrientation.Horizontal
};
BoxView avatarImage = new BoxView {
Color = Color.Red,
HeightRequest = 50,
WidthRequest = 50
};
horizontalLayout.Children.Add (avatarImage);
horizontalLayout.Children.Add (overlayContainerFrame);
ChatScrollViewStackLayout.Children.Add (horizontalLayout);
//ChatStackLayout.Children.Add (pic);
}
void CreateChatBubble() {
}
}
}
Does anyone have any ideas why I can't get the relative layout to resize accordingly so it doesn't go out of range of the screen? I tried setting its WidthConstraint to parent.With-52 to make up for the avatar taking up 50 units horizontally, but instead I get this:
I've been stuck at this for at least 8 hours now, and I'm pretty much out of ideas. Any tips would be greatly appreciated. Here is the project's git repo so you can clone it if you would like to test anything:
https://github.com/sgarcia-dev/xamarin-chat.git
Any help would be greatly appreciated, and feel free to completely ignore my code if it looks messy if you can replicate what I want. (One image on the left, and a message bubble on the right with an underlying image background)
Check out this implementation
void OnChatClick (object sender, EventArgs args) {
var pic = new Image {
Source = "bubble.png",
Aspect = Aspect.Fill
};
var textLabel = new Label {
Text = "Hello",
TextColor = Color.White,
VerticalOptions = LayoutOptions.Center,
LineBreakMode = LineBreakMode.WordWrap
};
var relativeLayout = new RelativeLayout {
BackgroundColor = Color.Navy,
// HeightRequest = 1000
};
var absoluteLayout = new AbsoluteLayout {
VerticalOptions = LayoutOptions.Center,
BackgroundColor = Color.Blue
};
var frame = new Frame {
BackgroundColor = Color.Red
};
absoluteLayout.Children.Add (pic,
new Rectangle (0, 0, 1, 1),
AbsoluteLayoutFlags.All);
absoluteLayout.Children.Add (textLabel,
new Rectangle (0.5, 0.5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize),
AbsoluteLayoutFlags.PositionProportional);
// textLabel.SizeChanged += (object label, EventArgs e) => {
// relativeLayout.HeightRequest = textLabel.Height + 30;
// absoluteLayout.HeightRequest = textLabel.Height + 30;
// };
relativeLayout.Children.Add (frame,
heightConstraint: Constraint.RelativeToParent (parent => parent.Height),
widthConstraint: Constraint.RelativeToParent (parent => parent.Width * 0.3));
relativeLayout.Children.Add (absoluteLayout,
xConstraint: Constraint.RelativeToParent (parent => parent.Width * 0.3),
widthConstraint: Constraint.RelativeToParent (parent => parent.Width * 0.7));
ChatScrollViewStackLayout.Children.Add (relativeLayout);
}
If you need to auto-adjust height of the chat message for long text uncomment all five commented lines.