Using OnIdiom with AbsoluteLayout - xaml

I have circular buttons and am trying to change the size of them depending on if they are on phone or tablet using AbsolutLayout.
Here is my xaml:
<Frame BackgroundColor="{StaticResource ThemeColor}" Padding="0" CornerRadius="40" AbsoluteLayout.LayoutBounds="{StaticResource HomeCircle}" AbsoluteLayout.LayoutFlags="PositionProportional">
<Label Text="" HorizontalOptions="Center" VerticalOptions="Center" Style="{StaticResource Icon}" TextColor="{StaticResource LabelColor}"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="Directions"/>
</Frame.GestureRecognizers>
</Frame>
<AbsoluteLayout.Resources>
<ResourceDictionary>
<OnIdiom x:Key="HomeCircle" x:TypeArguments="Frame" Phone=".85,.375, 80, 80"
Tablet=".85,.375, 120, 120"/>
</ResourceDictionary>
</AbsoluteLayout.Resources>
I looked at this resource and it did not work:
How to use attached properties such as Grid.Row, AbsoluteLayout.LayoutFlags to OnPlatform tag in Xamarin Forms
Edit: Have tried TypeArguments of Rectangle, AbsoluteLayout, and Frame and they all give this error:
Error XFC0009 No property, BindableProperty, or event found for "Phone", or mismatching type between value and property.
Edit: Have also looked at this thread and it provides the same error:
https://xamarin.github.io/bugzilla-archives/55/55183/bug.html

I faced the same problem in the past. My solution is to set the AbsoluteLayout bounds by Binding in place of StaticResource.
In the ViewModel:
public Xamarin.Forms.Rectangle HomeCircle => Xamarin.Forms.Device.Idiom == TargetIdiom.Phone ? new Xamarin.Forms.Rectangle(0.5f, 0.5f, 80, 80) : new Xamarin.Forms.Rectangle(0.5f, 0.5f, 120, 120);
In the yaml:
<AbsoluteLayout>
<Frame BackgroundColor="Gray"
Padding="0"
CornerRadius="40"
AbsoluteLayout.LayoutBounds="{Binding HomeCircle}"
AbsoluteLayout.LayoutFlags="PositionProportional">
<Label Text="TEST"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="Black"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding DoSomething}"/>
</Frame.GestureRecognizers>
</Frame>
</AbsoluteLayout>
Anyway AbsoluteLayout.LayoutBounds requires Rectangle, and markup doesn't always allow everything :)

Related

Resume and modify some graphic elements present in another page

I have created a ControlTemplate in the app.xaml, defining the graphic part, only in the cs I would like to take some elements, to which I have given the name, to assign them the click event, but it signals me that they do not exist in the current context .
Someone who could kindly tell me how to please?
Someone, if possible, modify the source of the webview present in the main page, directly from app.xaml.cs
My code in the template is this:`
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="HeaderFooterTemplate"><ContentPresenter />
<StackLayout>
<BoxView HorizontalOptions="FillAndExpand" BackgroundColor="#DDDDDD" HeightRequest="2" Margin="0" />
<ScrollView Orientation="Horizontal">
<Grid RowSpacing="0">
<StackLayout Background="#c9ced6" HeightRequest="120" MinimumHeightRequest="120" Orientation="Horizontal" Grid.Row="0" Spacing="2">
<Grid WidthRequest="100" MinimumHeightRequest="120" BackgroundColor="#373B53" Padding="10" x:Name="Dashboard">
<Image Source="homeArancione" x:Name="imgDashboard" HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="30" HeightRequest="30" Grid.Row="0" />
<Label Text="DASHBOARD" TextColor="#c9ced6" FontAttributes="Bold" HorizontalOptions="Center" Grid.Row="1" />
</Grid></Grid>
And in the reference page I recall it like this:
ControlTemplate="{StaticResource HeaderFooterTemplate}"
Graphically it works, but in the cs is I can't modify the texts to the labels or assign click events to the elements because it tells me that they don't exist in the current context
If you want to change the text or trigger the click event of the label in ControlTemplate, you could use the GestureRecognizers. The x:Name could not be found in the ControlTemplate directly.
<ControlTemplate x:Key="HeaderFooterTemplate">
<!--<ContentPresenter />-->
<StackLayout>
<BoxView HorizontalOptions="FillAndExpand" BackgroundColor="#DDDDDD" HeightRequest="2" Margin="0" />
<ScrollView Orientation="Horizontal">
<Grid RowSpacing="0">
<StackLayout Background="#c9ced6" HeightRequest="120" MinimumHeightRequest="120" Orientation="Horizontal" Grid.Row="0" Spacing="2">
<Grid WidthRequest="100" MinimumHeightRequest="120" BackgroundColor="#373B53" Padding="10" x:Name="Dashboard">
<Image Source="homeArancione" x:Name="imgDashboard" HorizontalOptions="Center" VerticalOptions="Center" WidthRequest="30" HeightRequest="30" Grid.Row="0" />
<Label Text="DASHBOARD" TextColor="#c9ced6" FontAttributes="Bold" HorizontalOptions="Center" Grid.Row="1">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
</Label.GestureRecognizers>
</Label>
</Grid>
</StackLayout>
</Grid>
</ScrollView>
</StackLayout>
</ControlTemplate>
Code behind: App.xaml.cs
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
Console.WriteLine("-----------");
var label = sender as Label;
label.Text = "Hello";
}
Update:
update the text of the label as soon as the page loads, without
having to click
Xamarin provide GetTemplateChild to get a named element from a template. The GetTemplateChild method should only be called after the OnApplyTemplate method has been called. If you want to call the OnApplyTemplate method, this template should be added for the contentpage.
You could refer to the thread i done before.
Xamarin SwipeView Open Left Item In ControlTemplate

Xamarin.Forms - My ControlTemplate doesn't respect HeightRequest

I have created a BottomBar in my App.xaml and I am using ControlTemplate to call it into the Xaml file of a different page.
My problem is: I have tried using HeightRequest inside the Layout in my App.xaml file, also tried using it in the Xaml file of the other page when calling it, and nothing seems to work. The page doesn't respect the HeightRequest.
I want them all to have the same height on every page (60).
page1
page2
page3
As you can see, the bottom bar has a different size on each page.
My App.xaml:
<ControlTemplate x:Key="CartTemplate" >
<AbsoluteLayout
x:Name="CartSection"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
BackgroundColor="#004EFF"
HeightRequest="60">
<Image Source="caricon"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
AbsoluteLayout.LayoutBounds="0.5,0.5"
AbsoluteLayout.LayoutFlags="PositionProportional"/>
<Grid
HeightRequest="22"
IsVisible="{TemplateBinding BindingContext.OrderCountVisible}"
WidthRequest="22"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
AbsoluteLayout.LayoutBounds="0.5,0.5"
AbsoluteLayout.LayoutFlags="PositionProportional"
Padding="25,0,0,10">
<Ellipse Fill="White"/>
<Label
Text="{TemplateBinding BindingContext.cartNumberItems}"
HorizontalOptions="CenterAndExpand"
TextColor="#004EFF"
FontAttributes="Bold"
FontSize="14"
Padding="0,0,0,3"
FontFamily="{StaticResource Helvetica}"/>
</Grid>
<AbsoluteLayout.GestureRecognizers>
<TapGestureRecognizer Command="{TemplateBinding BindingContext.CarCommand}" />
</AbsoluteLayout.GestureRecognizers>
</AbsoluteLayout>
</ControlTemplate>
This is how I am calling the Template (At the bottom just above the end tags):
<TemplatedView ControlTemplate="{StaticResource CartTemplate}"/>
</StackLayout>
</ContentPage.Content>
Thanks in advance.

Xamarin Style IndicatorView to look like TabbedPage

I have a problem. I recently had this problem: Xamarin forms Add button in TabbedPage, but that is fixed using the accepted anwser. In short, I am using a CarouselView and an IndicatorView, so I can have an overlay over multiple screens. Both the views replace my TabbedPage, but the IndicatorView needs to look like the TabbedPageBar. The only good page about styling an IndicatorView was this one: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/indicatorview.
Here is the page I have:
<StackLayout AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
Padding="0"
Spacing="0">
<IndicatorView x:Name="indicatorView">
<IndicatorView.IndicatorTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="FillAndExpand">
<Frame Margin="10">
<Label/>
</Frame>
</StackLayout>
</DataTemplate>
</IndicatorView.IndicatorTemplate>
</IndicatorView>
<CarouselView ItemTemplate="{StaticResource templateSelector}"
IndicatorView="indicatorView">
<CarouselView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>1</x:String>
<x:String>2</x:String>
<x:String>3</x:String>
</x:Array>
</CarouselView.ItemsSource>
</CarouselView>
</StackLayout>
Now how can I let the IndicatorView look like a TabbedPageBar?
I think the key point here is remove the Shadow and CornerRadius of Frame, then you can customize the layout in the Frame. Here is an example:
<IndicatorView x:Name="indicatorView" >
<IndicatorView.IndicatorTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="FillAndExpand" Spacing="0">
<Frame HasShadow="False" CornerRadius="0">
<StackLayout Orientation="Vertical">
<Image Source="Images"/>
<Label Text="123" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</IndicatorView.IndicatorTemplate>
</IndicatorView>

How to create below type of custom progress bar in xamarin forms

How To develop this type of Design(I have attached image below)
Supposedly you are referring to the bars, not the overall layout, but it's not 100% clear from your question. While there are other possibilities to display the bars, I achieved quite a satisfying result by nesting an AbsoluteLayout in a frame. See the following example for one of the bars on the right
<Frame HasShadow="False" HeightRequest="20" CornerRadius="5" HorizontalOptions="Fill" Padding="0" BackgroundColor="Silver" IsClippedToBounds="True">
<AbsoluteLayout>
<ContentView AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,.33,1"
BackgroundColor="CadetBlue">
<Label Text="33%"
FontSize="Small"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="White"
FontAttributes="Bold" />
</ContentView>
</AbsoluteLayout>
</Frame>
The bar itself is wrapped by a Frame to get the rounded corners (see the CornerRadius property). Setting IsClippedToBounds to true is necessary, because otherwise the children won't be clipped and the rounded corners do not show.
Within the Frame there is the AbsoluteLayout the actual bars are placed in. And within, I added the dark-greenish bar as a ContentView (to be able to add a label with the percentage).
Please see the following code for one of the green/red bars. Basically it's the same, but I added two sub-bars within the absolute layout
<Frame HasShadow="False" HeightRequest="20" CornerRadius="5" HorizontalOptions="Fill" Padding="0" BackgroundColor="Silver" IsClippedToBounds="True">
<AbsoluteLayout>
<ContentView AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,.25,1"
BackgroundColor="LimeGreen">
<Label Text="25%"
FontSize="Small"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="White"
FontAttributes="Bold" />
</ContentView>
<ContentView AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="1,0,.75,1"
BackgroundColor="Red">
<Label Text="75%"
FontSize="Small"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="White"
FontAttributes="Bold" />
</ContentView>
</AbsoluteLayout>
</Frame>
Generalization
It'd be useful to extract a re-usable component. I will show for the simpler bar. Transferring the solution to the more complex one should be easy, though.
Code behind
In the code behind the following properties have to be added
public Rectangle FirstBarBounds => new Rectangle(0, 0, BarValue, 1);
public double BarValue
{
get => this._barValue;
set
{
if (this._barValue == value)
{
return;
}
this._barValue = value;
this.OnPropertyChanged();
}
}
(Adding a BindableProperty for BarValue could be useful, too, but admittedly I was too lazy.)
The properties can be bound to from XAML
<Frame ...>
<AbsoluteLayout>
<ContentView AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="{Binding FirstBarBounds}"
BackgroundColor="CadetBlue" >
<Label Text="{Binding FirstBarValue, StringFormat='{}{0:P0}'}"
FontSize="Small"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="White"
FontAttributes="Bold" />
</ContentView>
</AbsoluteLayout>
</Frame>
The LayoutBounds of the ContentView is bound to BarBounds (which in turn uses BarValue to determine the bounds of the bar) and the text is bound to BarValue. Since BarValue is a double, the value is formatted to a percentage by StringFormat='{}{0:P0}'.
Screenshot
Please see the following screen shot on how the bars are rendered on an Android device (Emulator).

Frame corner radius not rounding corners on iOS

I am trying to round the corners of a stack layout, it works on android but on iOS, they still appear square but it does display the Frame shadow
My XAML is
<ContentPage.Content>
<StackLayout BackgroundColor="WHITE">
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Frame CornerRadius="10" Padding="0" Margin="10, 10, 10, 10">
<StackLayout>
. . .
</StackLayout>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
Set IsClippedToBounds property to Frame control:
<Frame IsClippedToBounds="True" CornerRadius="10" Padding="0" Margin="10, 10, 10, 10">
<StackLayout>
</StackLayout>
</Frame>
they still appear square
Actually, the Frame is round not the StackLayout, we just use Frame wrap it ,so it looks the StackLayout has round corners.
Frame
<Frame CornerRadius="10" Padding="0" Margin="10, 10, 10, 10" HasShadow="False" BackgroundColor="Red">
<StackLayout >
<Label Text="{Binding}"/>
</StackLayout>
</Frame>
StackLayout
<Frame CornerRadius="10" Padding="0" Margin="10, 10, 10, 10" HasShadow="False" >
<StackLayout BackgroundColor="Red">
<Label Text="{Binding}"/>
</StackLayout>
</Frame>
it does display the Frame shadow
You can disable it by HasShadow="False".
Actually I believe, it is a bug of Xamarin.Forms. UWP, Android and iOS should behave the same, but they don't. As a result to implement the same behaviour developers need to use OnPlatform feature.
The bug is described and discussed here, it is still open: https://github.com/xamarin/Xamarin.Forms/issues/2405