Border opacity wthout specifing background colour in .NET MAUI app - xaml

I have a simple, un-themed Maui app. Maui's default colour binding works as expected when I change the Windows theme between dark and light, which is what I want.
I have a Border object that is part of a Grid layout and which is positioned over some other elements. For visual design reasons I want the other elements to be partly visible through it, so I set its Opacity to 0.75. I don't specify its background colour because I want it to use the default for the current system theme. This worked until recently, but now the opacity only seems to be applied if a background colour is also explicitly specified - which I don't want to do for the reason described above. Is there a way to have a partly-opaque Border without hard-coding a background colour?
The following xaml is a cut-down example:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp1.MainPage">
<Grid>
<VerticalStackLayout
Grid.Row="0" Grid.Column="0">
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
</VerticalStackLayout>
<Border
Opacity="0.75"
Grid.Row="0" Grid.Column="0" ZIndex="99"
HorizontalOptions="Start" VerticalOptions="Start"
WidthRequest="200" HeightRequest="100"
Stroke="white" StrokeThickness="3"/>
</Grid>
</ContentPage>
Running this gives me the following result where the Label elements are not opaqued by the Border:
If I change the Border element's xaml to include, for example, BackgroundColor="LightGreen" then I get the following result, where the Label elements are opaqued by the Border:
I do want the opaqueness but I don't want to hard-code a background colour - I want Maui to choose the appropriate one depending on the system theme. How can I achieve this? Do I have to theme the app and tightly specify element colours?
(I'm targeting Windows and Mac only using .net 6 in current VS2022 mainline on Win11.)

Since you need a background color that an opacity can be applied to, you're required to set one, otherwise you'll be setting the opacity for a transparent background, which is pointless.
In order to achieve your goal of covering some content using a Border, you could just set the same color to your Border's background as the background of the page. Since you're working with Light and Dark only, assuming that this is set up with the AppThemeBinding, you could just do something like this:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp1.MainPage">
<Grid>
<VerticalStackLayout
Grid.Row="0" Grid.Column="0">
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
<Label Text="Hello world!"/>
</VerticalStackLayout>
<Border
BackgroundColor="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Black}}"
Opacity="0.75"
Grid.Row="0" Grid.Column="0" ZIndex="99"
HorizontalOptions="Start" VerticalOptions="Start"
WidthRequest="200" HeightRequest="100"
Stroke="white" StrokeThickness="3"/>
</Grid>
</ContentPage>
Essentially, your border just needs to be able to respond to changes to the app theme. You can find more information on how this works in the official documentation: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/system-theme-changes?view=net-maui-7.0

Related

How do I force child controls or layouts to be the same width as the parent in Xamarin Forms?

I have the following code.
<?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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="NGIC_XAML.Views.Payments.Payments">
<ContentPage.Content>
<FlexLayout Direction="Column" AlignItems="Center" HorizontalOptions="FillAndExpand">
<StackLayout BackgroundColor="Red" HeightRequest="108" HorizontalOptions="FillAndExpand">
<Label Text="Payments" TextColor="#F9F8FA" FontSize="20" Margin="40"
HorizontalTextAlignment="Center" VerticalOptions="Center"
HorizontalOptions="FillAndExpand">
</Label>
</StackLayout>
</FlexLayout>
</ContentPage.Content>
</ContentPage>
I want the outer layout, the FlexLayout, to automatically size the width to the device's maximum. I want the Layout (the StackLayout) and child Control (the Label), to also automatically resize their widths to the FlexLayout. I am stumped as to how to do this. Any suggestions?
In the FlexLayout docs, they mention "The HorizontalOptions property doesn't work for children of a FlexLayout".
If you take a look at the Page layout with FlexLayout section (Holy Grail Layout) you can see an example somewhat similar to what you are trying to accomplish, basically use a nested FlexLayout instead of a StackLayout.
The code would look like:
<ContentPage.Content>
<FlexLayout
BackgroundColor="Yellow"
Direction="Column">
<FlexLayout
HeightRequest="108"
AlignItems="Center"
Direction="Column"
BackgroundColor="Red">
<Label
BackgroundColor="Green"
LineBreakMode="CharacterWrap"
Text="Payments"
TextColor="#F9F8FA"
FontSize="20"
Margin="40"
HorizontalTextAlignment="Center"
VerticalOptions="Center">
</Label>
</FlexLayout>
</FlexLayout>
</ContentPage.Content>
And here is the screenshot:
Notice that the label will grow as needed to use the full width of the row.
To achieve this, please assign HorizontalOptions="FillAndExpand" to StackLayout and Label and other child controls if any.
This will tell the controls to fill all the space available horizontally.
Thanks!

How to wrap Label in FlexLayout

I am working with Xamarin Cross-platform, my primary target platform is UWP and secondary iOS.
I am trying to use FlexLayout within a ListView which may contain long label texts which I want to wrap within the FlexLayout Basis defined.
Here is the code I have written so far: I am using static data for simplicity, real data will be bonded dynamically.
<ListView.ItemTemplate>
<FlexLayout Direction="Row" Wrap="Wrap" Margin="0,10,0,10">
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="1. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="2. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="3.A long Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="4.A very loooooong Label header with long value"/>
<Label Text="A long Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="5. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="6. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="7. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="8. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="9. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" FlexLayout.Basis="300">
<Label Text="10. Label header"/>
<Label Text="Label Value"></Label>
</StackLayout>
</FlexLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This produces the following output:
Sample output
We can see that data of fourth stack (4.A very loooooong Label header with long value) is truncated.
But I want my output to be something like this: Desired Output
Things to remember here are:
I want to make maximum use of the space.
I don't prefer to use Wrap Layout.
The data can be of any length and I cannot define a minimum or maximum length of it.
The data is dynamic which will be bound at runtime, used static data here just for simplicity.
Want to have an equal width of every stack in every row, height must change according to data requirements.
I want to make maximum use of the space.
In my understanding, you are utilizing the max space available.
I don't prefer to use Wrap Layout.
Never heard of a wrap layout in xamarin forms but here if you mean you don't want to use LineBreakMode, then that is the only way possible for achieving your requirement.
The data can be of any length and I cannot define a minimum or maximum length of it.
That does not matter much the problem is not with the flex layout but the label setting the labels LineBreakMode property will do the trick
Where ever you feel that the text will be too long add something like this:
<Label ..... LineBreakMode="WordWrap"/>
The data is dynamic which will be bound at runtime, used static data here just for simplicity.
That changes nothing until your XAML is well written it will not behave weirdly
Want to have an equal width of every stack in every row, height must change according to data requirements.
In this case, I would suggest you wrap the StackLayout inside a Grid rather than a FlexLayout and then make the RowDefinitions, set to Auto so they fit themselves as per the need.

Access a Label placed inside a ContentView inside a ResourceDictionary

I have below XAML which contains ContentView inside my main XAML.
I want to know how can I access the LabelPushNotificationPrice to change the Text?
<?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:SyncfusionBusyIndicator="clr-namespace:Syncfusion.SfBusyIndicator.XForms;assembly=Syncfusion.SfBusyIndicator.XForms"
x:Class="ZayedAlKhair.InitiativeDetails"
xmlns:SyncfusionPopup="clr-namespace:Syncfusion.XForms.PopupLayout;assembly=Syncfusion.SfPopupLayout.XForms"
Title="زايد الخير">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="PushNotificationsViewTemplate">
<ContentView BackgroundColor="White" x:Name="PushNotificationsContentView">
<StackLayout Padding="15">
<Label HorizontalTextAlignment="End" Text="هذه الخدمة تمكنكم من إرسال تنبيهات الهواتف الذكية لجميع مشتركي تطبيق زايد الخير وهي أفضل خدمة لتصل مبادرتكم لآلاف المشتركين" HeightRequest="90" WidthRequest="100" />
<Label x:Name="**LabelPushNotificationPrice**" HorizontalTextAlignment="End" Text="سعر الخدمة : 499 دولار" HeightRequest="30" WidthRequest="100" />
<Label HorizontalTextAlignment="End" Text="مدة الترويج : مرة واحدة لكل مبادرة" HeightRequest="30" WidthRequest="100" />
</StackLayout>
</ContentView>
</DataTemplate>
<DataTemplate x:Key="PromoteViewTemplate">
<ContentView BackgroundColor="White" x:Name="PromoteContentView">
<StackLayout Padding="15">
<Label HorizontalTextAlignment="End" Text="هذه الخدمة ستجعل مبادرتكم مميزة باللون الأحمر ودائما في أعلى القائمة ليتمكن كل مستخدمي التطبيق من التعرف عليها والتفاعل معها" HeightRequest="90" WidthRequest="100" />
<Label HorizontalTextAlignment="End" Text="سعر الخدمة : 99 دولار" HeightRequest="30" WidthRequest="100" />
<Label HorizontalTextAlignment="End" Text="مدة التمييز : 30 يوما" HeightRequest="30" WidthRequest="100" />
</StackLayout>
</ContentView>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<Grid Padding="10" x:Name="GridInitiativeDetails">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
The preferred way is to use DataBindings, example:
<Label HorizontalTextAlignment="End" Text="{Binding LabelPushNotificationPrice}" />
This way you can seamlessly update the value of the Label bound to your ViewModel. The point is to separate UI layer from your BL layer and usually we use MVVM rather than MVC in Xamarin.Forms. The official documentation is nicely covering this topic and there are free e-books like Enterprise Application Patterns using Xamarin.Forms that I recommend to read additionally.
P.S.: Please note that setting a fixed Height & Width on UI controls may break your UX experience on screens with different sizes.

Add shadow to a Label - Xamarin.Forms

I would like to add drop shadow to a Label. This label is overlapped in the Page, like an always visible control that opens a filtering page.
Please find a gif attached with my screen:
Here's my XAML:
<!-- **** Filter button **** -->
<Label
Margin="0,0,10,10"
WidthRequest="50"
HeightRequest="50"
HorizontalOptions="End"
VerticalOptions="End"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
FontSize="30"
Style="{DynamicResource FilterAction}"
Text=""
BackgroundColor="{StaticResource ComplementColor}"
FontFamily="{x:Static artina:FontAwesome.FontName}"
TextColor="White">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding btn_open_filter_businesses_click}" />
</Label.GestureRecognizers>
</Label>
<templates:Badge
BadgeText="{Binding number_of_filters_selected}"
BadgeTextColor="White"
BadgeBackgroundColor="#1DBDFF"
HorizontalOptions="End"
VerticalOptions="End"
TranslationX="-4"
TranslationY="-4"
IsVisible="{Binding number_of_filters_selected, Converter={StaticResource filterVis}"
x:Name="filtersCountBagde">
<templates:Badge.GestureRecognizers>
<TapGestureRecognizer Command="{Binding btn_open_filter_businesses_click}" />
</templates:Badge.GestureRecognizers>
</templates:Badge>
I would like something like Gmail, find the example below:
Any help would be appreciated.
You can use Xamarin Effects to achieve a shadow on your button. There is a code sample that you can download here which should get you started:
Shadow Effect
It will involve creating platform-specific implementations for your shadow.
You could also try the idea put forward in this similar question.

How to change icon color in Xamarin.Forms xaml page?

Currently, I am developing a Xamarin.Forms PCL application for Android and iOS. In one of my pages I define a ListView. The template for the ListView.ItemTemplate displays an icon using <Image Source="some_Icon.png" />. The icon displays as expected (black) but I have not found a way to set the color.
I would like to colorize this icon based on logic in my ViewModel.
I have searched for answers both through the Documentation and StackOverlflow to no avail.
Is there a better way to display and style icons from a Xamarin.Forms PCL project?
Does Xamarin.Forms require a set of resource/image files for every possible color I might use?
I solved my problem with Iconize for Xamarin.Forms. I implemented my solution based off the Iconize sample code 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:iconize="clr-namespace:FormsPlugin.Iconize;assembly=FormsPlugin.Iconize"
x:Class="Iconize.FormsSample.Page1"
Title="{Binding FontFamily}">
<ContentPage.ToolbarItems>
<iconize:IconToolbarItem Command="{Binding ModalTestCommand}" Icon="fa-500px" />
<iconize:IconToolbarItem Command="{Binding VisibleTestCommand}" Icon="fa-500px" IconColor="Red" />
<iconize:IconToolbarItem Command="{Binding VisibleTestCommand}" Icon="fa-500px" IsVisible="{Binding VisibleTest}" />
</ContentPage.ToolbarItems>
<ListView CachingStrategy="RecycleElement" ItemsSource="{Binding Characters}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<iconize:IconImage HeightRequest="20" Icon="{Binding Key}" IconColor="Blue" WidthRequest="20" />
<iconize:IconImage HeightRequest="20" Icon="{Binding Key}" BackgroundColor="Blue" IconColor="Yellow" WidthRequest="20" IconSize="10" />
<iconize:IconButton FontSize="20" Text="{Binding Key}" TextColor="Red" WidthRequest="48" />
<iconize:IconLabel FontSize="20" Text="{Binding Key}" TextColor="Green" VerticalTextAlignment="Center" />
<Label Text="{Binding Key}" VerticalTextAlignment="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
In my case, I simply had to replace my original <Image .../> element and replace it with
<iconize:IconImage HeightRequest="20" Icon="fa-circle" IconColor="{Binding CircleColor}" WidthRequest="20" />.
In my ViewModel, I added the CircleColor property to set the icon color as needed based on my logic.