figure out how many circular frames fit on screen xamarin.forms - xamarin.forms

I want to create a grid with circular frames according to the number of students in a class. i want to display them i a way that the number of frames in each column fit the screen and i'll have rows added accordingly, so i tried to do something like this as a trial:
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"
x:Class="stdprofiles.MainPage">
<StackLayout Orientation="Horizontal" >
<Grid x:Name="thislayout" HorizontalOptions="Center" Margin="20,20" >
</Grid>
</StackLayout>
</ContentPage>
xaml.cs:
public MainPage()
{
InitializeComponent();
var width = DeviceDisplay.MainDisplayInfo.Width;
var height = DeviceDisplay.MainDisplayInfo.Height;
double nbofcolumns = width / 150;
double nbofrows = 10 / nbofcolumns;
double ans = nbofcolumns * nbofrows;
for (int i = 0; i < nbofcolumns-1; i++)
{
thislayout.ColumnDefinitions.Add(new ColumnDefinition { Width = 100 });
}
for (int j=0;j< nbofrows+1; j++)
{
thislayout.RowDefinitions.Add(new RowDefinition { Height = 100 });
}
for(int i=0;i<10;i++)
{
SwipeItem delete = new SwipeItem
{
IconImageSource="deleteic.png",
BackgroundColor = Color.Transparent
};
List<SwipeItem> swipeItems = new List<SwipeItem>() { delete };
Frame circleImageFrame = new Frame
{
ClassId=i.ToString(),
Margin = 10,
BorderColor = Color.Black,
CornerRadius = 50,
HeightRequest = 100,
WidthRequest = 100,
IsClippedToBounds = true,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Content = new Image
{
Source = ImageSource.FromFile("user_profile.png"),
Aspect = Aspect.AspectFill,
Margin = -20,
HeightRequest = 100,
WidthRequest = 100
}
};
SwipeView swipe = new SwipeView
{
TopItems = new SwipeItems(swipeItems),
Content=circleImageFrame
};
thislayout.Children.Add(swipe, i%(int)nbofcolumns, i/(int)nbofcolumns);
delete.Invoked += delegate
{
thislayout.Children.Remove(swipe);
};
}
}
the point is that i got the width of my phone screen then divided it by 150 because i specified that i want my column's width to be 100. the thing is that it's not working, the number of columns obtained do not fit the screen like i got 7 columns and only 4 columns fit the rest do not appear and so i didn't get correct number of rows. another thing surprised me is that when i tried displaying the width obtained I got 1080 (for my phone) but when I used a tablet I got 800 though my tablet I bigger than my phone. how come? something seems odd and I don't know what it is. any suggestions?

Related

Issue while setting slider thumb at a particular point if slider maximum value is too high?

I am working in xamarin forms. I have slider whose maximum value is more than 200. I want to move the slider thumb at particular point on slider for example at 120, but it becomes very tough to put the thumb at particular point. This happens with large maximum values. If values are less then its working fine.
So is there any solution so that we can move the slider's thumb easily at any point if slider's maximum value is very large?
You can set the increase value like this GIF.
Here is code.I set the StepValue to 20
public partial class MainPage : ContentPage
{
private double StepValue;
private Slider SliderMain;
public MainPage()
{
InitializeComponent();
StepValue = 20.0;
BindingContext = new HslColorViewModel();
SliderMain = new Slider
{
Minimum = 0.0f,
Maximum = 200.0f,
Value = 0.0f,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand
};
SliderMain.BackgroundColor = Color.Black;
SliderMain.ValueChanged += OnSliderValueChanged;
Content = new StackLayout
{
Children = { SliderMain },
Orientation = StackOrientation.Vertical,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs e)
{
var newStep = Math.Round(e.NewValue / StepValue);
SliderMain.Value = newStep * StepValue;
}
}

Xamarin.Forms create a custom control as a row in a Grid layout

Say I have a list of items displayed as a Grid layout. Each item takes up a row and is made up of multiple items in a column. It's basically a table:
<Grid>
<Label Text="Item1" Grid.Row="0" Grid.Colum="0" />
<Image Src="something1" Grid.Row="0" Grid.Colum="1" />
<Label Text="Item2" Grid.Row="1" Grid.Colum="0" />
<Image Src="something2" Grid.Row="1" Grid.Colum="1" />
<Label Text="Item3" Grid.Row="2" Grid.Colum="0" />
<Image Src="something3" Grid.Row="2" Grid.Colum="1" />
</Grid>
Each Label/Image represents a row in my list of items to be displayed. I'm not worried about the databinding for the moment, I just want to move the Label/Image into a custom control so that I can use that custom control to add "Rows" into my Grid:
<Grid>
<customcontrol:MyCustomRowControl Text="Item1" Source="img1" Grid.Row="0"/>
<customcontrol:MyCustomRowControl Text="Item2" Source="img1" Grid.Row="1"/>
<customcontrol:MyCustomRowControl Text="Item3" Source="img1" Grid.Row="3"/>
</Grid>
I can probably set the Lable/Image/etc from my custom control to it's appropriate row/column from the code-behind.Where I get lost is what type of base class should I make this custom control? Because it is that class that will become the content of the Grid, not it's Labels and Images, therefore the Grid.Row and Grid.Column will not propagate correctly. I really hope I managed to explain this.
Can I create a custom control in Xamarin that I can add as a content to a Grid and have it's children respect the Grid's columns?
You can write about like this
DynamicGridView class
public class DynamicGridView : Grid
{
private int _rowCount;
private int _columnCount;
protected int _column;
protected int _starHeight = 0;
protected int _type;
protected int[] _starHeightList;
public DynamicGridEnum _dynamicGridEnum;
public DynamicGridView(DynamicGridEnum dynamicGridEnum, params int[] starHeightList)
{
_type = 2;
switch (dynamicGridEnum)
{
case DynamicGridEnum.Auto:
_column = starHeightList[0];
break;
case DynamicGridEnum.Star:
_column = starHeightList[0];
_starHeight = starHeightList[1];
_type = 1;
break;
case DynamicGridEnum.Custom:
_column = starHeightList.Length;
break;
default:
break;
}
_starHeightList = starHeightList;
_dynamicGridEnum = dynamicGridEnum;
_rowCount = 0;
_columnCount = 0;
Padding = 0;
Margin = 0;
ColumnSpacing = -1;
RowSpacing = -1;
}
public virtual void AddView(View view)
{
int countRow = _rowCount / _column;
if (RowDefinitions.Count <= countRow)
{
RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, (GridUnitType)_type) });
}
Children.Add(view, _columnCount, countRow);
_rowCount++;
_columnCount++;
_columnCount = _columnCount % _column;
}
}
DynamicGrid class
public class DynamicGrid : DynamicGridView
{
public DynamicGrid(DynamicGridEnum dynamicGridEnum, params int[] starHeightList) : base(dynamicGridEnum, starHeightList)
{
for (int i = 0; i < starHeightList.Length; i++) { starHeightList[i] = starHeightList[i] <= 0 ? 1 : starHeightList[i]; }
if (dynamicGridEnum == DynamicGridEnum.Custom)
{
StartCustomGrid();
}
else
StartGrid();
}
private void StartGrid()
{
int percent = 100 / _column;
for (int i = 0; i < _column; i++)
ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(percent, (GridUnitType)_type) });
}
private void StartCustomGrid()
{
foreach (var item in _starHeightList)
ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(item, GridUnitType.Star) });
}
}
And usage of dynamic grid (I defined an enum for type of grid. For
example if enum is auto it will be auto resize row/columns of grid.)
public partial class MainPage : ContentPage
{
public MainPage()
{
StackLayout sl = new StackLayout();
DynamicGrid dynamicGrid = new DynamicGrid(Enums.DynamicGridEnum.Custom, 20, 50, 20, 0);
dynamicGrid.AddView(new BoxView() { BackgroundColor = Color.AliceBlue });
dynamicGrid.AddView(new BoxView() { BackgroundColor = Color.Aqua });
dynamicGrid.AddView(new BoxView() { BackgroundColor = Color.AntiqueWhite });
dynamicGrid.AddView(new BoxView() { BackgroundColor = Color.Azure });
sl.Children.Add(new CardView(Color.Beige, Color.Bisque, 60, Color.Black, 90, 10));
sl.Children.Add(dynamicGrid);
Content = sl;
}
}

ZXingBarcodeImageView rendering aspect ration on iOS virtual device

I am trying to generate and display barcode in Xamarin forms using following code.
barcode = new ZXingBarcodeImageView
{
HeightRequest = 400,
WidthRequest = 400
};
barcode.BarcodeFormat = ZXing.BarcodeFormat.QR_CODE;
barcode.BarcodeOptions.Width = 400;
barcode.BarcodeOptions.Height = 400;
barcode.BarcodeOptions.Margin = 10;
barcode.BarcodeValue = "ZXing.Net.Mobile";
Content = barcode;
The QR code is rendered fine in Android virtual device. On the other hand, in iOS device, a distorted QR code is rendered. The aspect ration of QR code rendered on iOS virtual device is not square as it supposed to be.
The QR code rendered on Android virtual device is verified using a mobile phone.
Edit:
Tried the following code as suggested by #wilson
try
{
barcode = new ZXingBarcodeImageView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
};
barcode.BarcodeFormat = ZXing.BarcodeFormat.QR_CODE;
barcode.BarcodeOptions.Width = 500;
barcode.BarcodeOptions.Height = 500;
barcode.BarcodeOptions.Margin = 10;
barcode.BarcodeValue = "ZXing.Net.Mobile";
Content = barcode;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
Still, I see the same problem. When I tried the example code of #wilson and it works fine on iPhone simulator. Probably I should use content view as suggested.
Edit 2
I tried the stack layout as shown below.
<?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:AZCommute"
x:Class="AZCommute.MainPage">
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="QR Code Generator" HorizontalOptions="Center"/>
<local:QRResult x:Name="qrResult"/>
</StackLayout>
</ContentPage>
But, it was of no help. Nothing rendered on iOS. I tried by adding WidthRequest and HeightRequest while initializing the ZXingBarcodeImageView as shown below.
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
WidthRequest = 410,
HeightRequest = 410,
Now, ZXingBarcodeImageView renders in iPhone simulator. But, the aspect ratio is lost (height > width ).
Note: I am using the ContentView with StackLayout
Try assigning the HorizontalOptions property like this:
barcode = new ZXingBarcodeImageView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
};
barcode.BarcodeFormat = ZXing.BarcodeFormat.QR_CODE;
barcode.BarcodeOptions.Width = 500;
barcode.BarcodeOptions.Height = 500;
barcode.BarcodeValue = contentEntry.Text.Trim();
Content = barcode;
Or try creating a ContentView to show QRCode.
For more information see my example.
Try to put inside a StackLayout :)
barcode = new ZXingBarcodeImageView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
};
barcode.BarcodeFormat = ZXing.BarcodeFormat.QR_CODE;
barcode.BarcodeOptions.Width = 500;
barcode.BarcodeOptions.Height = 500;
barcode.BarcodeOptions.Margin = 10;
barcode.BarcodeValue = "ZXing.Net.Mobile";
Content = new StackLayout{
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
Children = {
barcode
}
};

Right-aligned Labels in iOS

I'm using Xamarin Forms. Some of my labels are right-adjusted (i.e TextAlignment = TextAlignment.End) and have a whitespace character in the end to allow a bit of a margin at the right end. This works as designed in Android. However, it looks like iOS simply ignores the trailing space.
A leading space, for left-adjusted labels, works fine on both platforms.
I tried different whitespace characters other than "\u0020": "\u00A0", "\u2000", "\u202F", etc. iOS ignores them all the same.
I cannot use Label.Margin because my label has a different BackgroundColor, and the whole idea is to leave a little space of this color at the right of the text. The Margin is considered outside of the label, so the background color won't extend there.
Is placing the label inside a ContentView with Padding the only solution?
Answer
You're correct: we need to increase the Label's Padding, and Margin won't accomplish this!
The problem is that Label doesn't have a Padding property.
I recommend setting the BackgroundColor and Padding in the Layout that holds the Label:
Remove the BackgroundColor from the Label
Assign the BackgroundColor to the Layout
Set the Padding of the Layout
var stackLayout = new StackLayout
{
Children = { rightJustifiedLabel },
BackgroundColor = Color.Red,
Padding = new Thickness(0, 0, 5, 0)
}
Sample Code
public class App : Application
{
public App()
{
MainPage = new LabelPage();
}
}
public class LabelPage : ContentPage
{
public LabelPage()
{
var rightJustifiedLabel = new Label
{
Text = "Right-Justified Label",
HorizontalTextAlignment = TextAlignment.End,
};
Content = new StackLayout
{
Children = { rightJustifiedLabel },
BackgroundColor = Color.Red,
Padding = new Thickness(0, 0, 5, 0),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
}
}

Xamarin Forms DisplayAlert Button TextColor

How would I change the Button text color on a Xamarin Forms DisplayAlert dialog?
FWIW, I opted to create a new ContentPage in XAML and show it with Navigation.PushModalAsync. In my case, it was the easiest way to simulate an alert and maintain control of all the styles.
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"
x:Class="YourNamespace.AlertPage"
BackgroundColor="DarkGray"
Padding="40">
<ContentPage.Content>
<StackLayout BackgroundColor="White" Padding="10">
<Label x:Name="lblTitle" FontAttributes="Bold" FontSize="Large" Text="Title" HorizontalOptions="Center"></Label>
<BoxView HeightRequest="1" BackgroundColor="DarkGray"></BoxView>
<ScrollView Orientation="Vertical" VerticalOptions="FillAndExpand">
<Label x:Name="lblText" FontSize="Medium"></Label>
</ScrollView>
<BoxView HeightRequest="1" BackgroundColor="DarkGray"></BoxView>
<StackLayout Orientation="Horizontal">
<Button x:Name="btn1" Text="Button 1" HorizontalOptions="CenterAndExpand"></Button>
<Button x:Name="btn2" Text="Button 2" HorizontalOptions="CenterAndExpand"></Button>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
C#:
public partial class AlertPage : ContentPage
{
public Label LblTitle
{
get
{
return lblTitle;
}
}
public Label LblText
{
get
{
return lblText;
}
}
public Button Button1
{
get
{
return btn1;
}
}
public Button Button2
{
get
{
return btn2;
}
}
public AlertPage()
{
InitializeComponent();
}
}
Implementation:
var ap = new AlertPage();
ap.LblTitle.Text = "Instructions";
ap.LblText.Text = "The text to display!";
ap.Button1.Text = "Done";
ap.Button1.Clicked += async (s, a) =>
{
await Navigation.PopModalAsync();
};
ap.Button2.IsVisible = false;
await Navigation.PushModalAsync(ap);
Screenshot:
Possible to change color with the help of custom renderers for each platform.
You have access to native api inside custom renderer.
But need to be sure that is needed, because it is not recommended (for iOS sure).
The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified.
Relative topic for iOS here.
i have created custom displayalert you can use task call back TaskCompletionSource as xamarin build DisplayAlert from it
public async Task<bool> ShowDialogAsync(string title, string message, string acceptMessage, string cancelMessage)
{
Grid ShowDialogMessage = null;
Grid CurrentPageGrid = (App.Instance.CurrentPage as ContentPage).Content as Grid;
TaskCompletionSource<bool> result = new TaskCompletionSource<bool>();
try
{
ShowDialogMessage = GenericView.CustomDisplayAlert(message, CurrentPageGrid.RowDefinitions.Count, CurrentPageGrid.ColumnDefinitions.Count, () =>
{
//here you can add your implementation
CurrentPageGrid.Children.Remove(ShowDialogMessage);
result.SetResult(true);
},
() =>
{
//here you can add your implementation
CurrentPageGrid.Children.Remove(ShowDialogMessage);
result.SetResult(false);
}, title, acceptMessage, cancelMessage);
CurrentPageGrid.Children.Add(ShowDialogMessage);
return await result.Task;
}
catch (Exception ex)
{
return await App.Current.MainPage.DisplayAlert(title, message, acceptMessage, cancelMessage);
#if DEBUG
throw ex;
#endif
}
}
in my method i added actions to implement the call back ,, method signature you can add your own design
public static Grid CustomDisplayAlert(string message, int rows, int columns, Action acceptAction, Action cancelAction, string title = "", string acceptMessage = "", string cancelMessage = "")
{
Grid overlay = new Grid
{
BackgroundColor = Color.FromRgba(0, 0, 0, 190),
RowDefinitions = new RowDefinitionCollection { new RowDefinition { Height = GridLength.Star }, new RowDefinition { Height = GridLength.Auto }, new RowDefinition { Height = GridLength.Star } }
};
Grid.SetRowSpan(overlay, rows);
Grid.SetColumnSpan(overlay, columns);
Grid bodyView = new Grid();
StackLayout stackMainView = new StackLayout
{
Margin = new Thickness(20)
};
StackLayout stackButtonsView = new StackLayout
{
Orientation=StackOrientation.Horizontal
};
RoundedBox bgOverlay = new RoundedBox
{
CornerRadius = 4,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.White
};
bodyView.Children.Add(bgOverlay);
StackLayout elementsContainer = new StackLayout { Margin = new Thickness(10) };
IconicLabel itemDescription = new IconicLabel { MoreReadable = true, Text = message, StyleId = "Myriad-Pro-L", HorizontalTextAlignment = TextAlignment.Center, HorizontalOptions = LayoutOptions.FillAndExpand, TextColor = (Color)(App.Current.Resources["OptioDark"]), FontSize = 18, Margin = new Thickness(15) };
IconicLabel titleView = new IconicLabel { FontAttributes = FontAttributes.Bold, MoreReadable = true, Text = title, StyleId = "Myriad-Pro-L", HorizontalTextAlignment = TextAlignment.Center, HorizontalOptions = LayoutOptions.FillAndExpand, TextColor = (Color)(App.Current.Resources["OptioDark"]), FontSize = 22, Margin = new Thickness(15) };
if (titleView.Text.Length != 0)
elementsContainer.Children.Add(titleView);
elementsContainer.Children.Add(itemDescription);
bodyView.Children.Add(elementsContainer);
IconicButton acceptBtn = new IconicButton
{
HeightRequest = 40,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.White,
Text = acceptMessage,
TextColor = (Color)(App.Current.Resources["OptioDark"])
};
IconicButton cancelBtn = new IconicButton
{
HeightRequest = 40,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.White,
Text = cancelMessage,
TextColor = (Color)(App.Current.Resources["OptioDark"])
};
acceptBtn.Clicked += (sender, e) =>
{
acceptAction?.Invoke();
};
cancelBtn.Clicked += (sender, e) =>
{
cancelAction?.Invoke();
};
stackButtonsView.Children.Add(acceptBtn);
stackButtonsView.Children.Add(cancelBtn);
stackMainView.Children.Add(bodyView);
stackMainView.Children.Add(stackButtonsView);
overlay.Children.Add(stackMainView, 0, 1);
return overlay;
}

Resources