C# grid on top of image - xamarin

I am fairly new to Xamarin and XAML, so forgive me if my question is dumb.
I have an image that sits inside of an absolute layout content, the image is larger than the screen width and height (pinch and pan works). I am now trying to create a grid that sits on top of the image and eventually populate each cell with a button (a crude way of getting X,Y position). It is crude, I'll admit it, but I would like to do it, if anything, I'll learn what not to do.
This is my XAML,
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyProject.Code"
x:Class="MyProject.Views.myImage"
HeightRequest="771"
WidthRequest="900">
<ContentPage.Content>
<AbsoluteLayout HorizontalOptions="FillAndExpand">
<local:PinchAndPanContainer>
<Image Source="map.png"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Aspect="Fill"
Opacity="50"/>
</local:PinchAndPanContainer>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
And this is my .cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyProject.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class myImage: ContentPage
{
public myImage()
{
InitializeComponent();
// Creates the grid
InitializeGrid(2);
}
void InitializeGrid(int res)
{
Grid grid = new Grid();
var red = new BoxView { Color = Color.Red };
var grn = new BoxView { Color = Color.Green };
var blu = new BoxView { Color = Color.Blue };
var yel = new BoxView { Color = Color.Yellow };
grid.WidthRequest = 900;
grid.HeightRequest = 771;
grid.VerticalOptions = LayoutOptions.FillAndExpand;
grid.HorizontalOptions = LayoutOptions.FillAndExpand;
for (int MyCount = 0; MyCount < res; MyCount++)
{
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
}
grid.Children.Add(red, 0, 0);
grid.Children.Add(grn, 0, 1);
grid.Children.Add(blu, 1, 0);
grid.Children.Add(yel, 1, 1);
}
}
}
How can I achieve a 2x2 grid that will sit on top of the image? I would like to take the C# route in creating the grid so I can create a loop and pass in the "resolution" of the grid, 3x3, 100x100, etc.
When I execute this, nothing happens. Even if I comment out almost the entire XAML that displays the image, I still get nothing. Not sure where to go from here.

Add a name to your AbsoluteLayout (i.e. x:Name="layout") so you can parent your grid to it via .Children.Add
I made a few 😎 more changes to your InitializeGrid method to setup the grid within the AbsoluteLayout properly
FYI: Creating grids with a large number of elements will be a huge performance issue.
Example:
void InitializeGrid(int res)
{
var grid = new Grid
{
RowSpacing = 0,
ColumnSpacing = 0
};
AbsoluteLayout.SetLayoutBounds(grid, new Rectangle(1, 1, 1, 1));
AbsoluteLayout.SetLayoutFlags(grid, AbsoluteLayoutFlags.All);
for (int MyCount = 0; MyCount < res; MyCount++)
{
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
}
grid.Children.Add(new BoxView { Color = Color.Red, Opacity=0.5 }, 0, 0);
grid.Children.Add(new BoxView { Color = Color.Green, Opacity = 0.5 }, 0, 1);
grid.Children.Add(new BoxView { Color = Color.Blue, Opacity = 0.5 }, 1, 0);
grid.Children.Add(new BoxView { Color = Color.Yellow, Opacity = 0.5 }, 1, 1);
layout.Children.Add(grid);
}
Output:

Related

How to bind in Codebehind from a global variable in App class in Xamarin

I'm trying to create an NavigationPage TitleView with traditional Cart Icon saying (3) Items etc.
So the global CartCount variable is Declared in App class.
My CommonToolbarPage class Lays out the top of all 50 pages with Logo, search button and Cart icon like every shop on the internet. I'm using Prism.
What I'm after is what goes here to bind to CartCount so BadgeText updates when the CartCount updates.
BadgeText = App.CartCount , // Jiberish
Cut down class
public class CommonToolbarPage : ContentPage
{
public CommonToolbarPage()
{
//NavigationPage.SetHasBackButton(this, false);
ShowDefaultTitle();
//this.BindingContext= new CommonToolbarPageViewModel(navigationService);
}
private void ShowDefaultTitle()
{
SfButton sfButton = new SfButton
{
CornerRadius = 4,
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Center,
Style = (Style)Application.Current.Resources["IconButtonStyle"],
Text = (String)Application.Current.Resources["Cart"],
FontFamily = "UIFontIcons",
TextColor = Color.White,
// Command = new Command(GoCart)
};
var Endlayout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.EndAndExpand,
};
var imSfBadgeView = new SfBadgeView
{
BadgeText = App.Cart, // Jiberish
Margin = new Thickness(0, 0, 10, 0),
Padding = new Thickness(0),
WidthRequest = 40,
// Content = sfButton,
HorizontalOptions = LayoutOptions.EndAndExpand,
VerticalOptions = LayoutOptions.Center,
BackgroundColor = Color.Transparent,
BadgeSettings = new BadgeSetting
{
BackgroundColor = (Color)Application.Current.Resources["PrimaryColor"],
BadgeType = BadgeType.None,
FontSize = 10,
Stroke = (Color)Application.Current.Resources["Gray-White"],
StrokeWidth = 1,
Offset = new Point(-10, 10)
}
};
Endlayout.Children.Add(imSfBadgeView);
NavigationPage.SetTitleView(this, Endlayout);
}
}
Each page then looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<local1:CommonToolbarPage xmlns:local1="clr-namespace:blaAppV1.Views.Templates"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:listview="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="http://prismlibrary.com"
prism:ViewModelLocator.AutowireViewModel="True"
xmlns:local="clr-namespace:blaAppV1.Views;assembly=blaAppV1"
x:Class="blaAppV1.Views.Home">
<StackLayout VerticalOptions="StartAndExpand" HorizontalOptions="Center">
<Label Text="Home" VerticalOptions="Center" HorizontalOptions="Center" />
<Button Text="Appliances" Command="{Binding Path=NavigateCommand}" CommandParameter="Appliances" />
</StackLayout>
</local1:CommonToolbarPage>
you use SetBinding to create a binding in code
myLabel.SetBinding(Label.TextProperty, "CartCount");
myLabel.BindingContext = App;

How to merge two image in Xamarin Forms?

I'm developing a Xamarin Forms iOS app. In the xaml file, there is a grid.
<Grid x:Name="QrCodeSite" HeightRequest="300" Margin="37, 37, 37, 0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
In the related .cs file, I use ZXing.Net.Mobile.Forms to generate a QR code and place it in the grid. And I put my logo in the same grid, which will finally appear at the center of the QR code.
var barcode = new ZXingBarcodeImageView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
barcode.BarcodeFormat = ZXing.BarcodeFormat.QR_CODE;
barcode.BarcodeOptions.Width = 650;
barcode.BarcodeOptions.Height = 650;
barcode.BarcodeOptions.Margin = 1;
barcode.BarcodeValue = value;
var img = new Image
{
Source = "logo.png",
WidthRequest = 70,
HeightRequest = 70,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};
QrCodeSite.Children.Clear();
QrCodeSite.Children.Add(barcode);
QrCodeSite.Children.Add(img);
The problem is, maybe my phone (iPhone 6s plus) is too slow, sometimes the logo appears first and after a lag (around 1 second) the QR code is shown. How can I merge the QR code and the logo into one image and then add it to the grid?
You can using SkiaSharp to display Image or merge images . Having a look at how to Display SkiaSharp bitmaps to download sample project to research at it.
Based on Drawing on existing bitmaps reference , you can modify it as follow :
public partial class MonkeyMoustachePage : ContentPage
{
SKBitmap monkeyBitmap;
public MonkeyMoustachePage()
{
Title = "Monkey Moustache";
monkeyBitmap = BitmapExtensions.LoadBitmapResource(GetType(),
"SkiaSharpFormsDemos.Media.MonkeyFace.png");
SKBitmap iconImage = BitmapExtensions.LoadBitmapResource(GetType(),
"SkiaSharpFormsDemos.Media.GooglePlaylogo.png");
int offset = monkeyBitmap.Width / 2 - iconImage.Width / 2;
int offsetTop = monkeyBitmap.Height / 2 - iconImage.Height / 2;
// Create canvas based on bitmap
using (SKCanvas canvas = new SKCanvas(monkeyBitmap))
{
canvas.DrawBitmap(iconImage, SKRect.Create(offset, offsetTop, iconImage.Width, iconImage.Height));
}
// Create SKCanvasView to view result
SKCanvasView canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
//save the new image
using (MemoryStream memStream = new MemoryStream())
using (SKManagedWStream wstream = new SKManagedWStream(memStream))
{
monkeyBitmap.Encode(wstream, imageFormat, quality);
byte[] data = memStream.ToArray();
// Check the data array for content!
bool success = await DependencyService.Get<IPhotoLibrary>().SavePhotoAsync(data, folder, filename);
// Check return value for success!
}
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.DrawBitmap(monkeyBitmap, info.Rect, BitmapStretch.Uniform);
}
}
Then you will see a logo icon will display in original image :
If you want to save SkiaSharp bitmaps to files , have a look at this :https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/bitmaps/saving#exploring-the-image-formats
Note: BitmapExtensions.cs file is from sample project .By the way , when adding image to project , you need to set Build ACtion of image be Embedded resource .As follow :

How to set auto fill to grid column width

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.

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.

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;

Resources