How can I set ResourceDictionary FontSize on XAML? - xamarin

Apologies if this would be a messy one. I'm pretty new to Xamarin. Currently I'm trying to convert this resource dictionary code to a XAML:
Current.Resources = new ResourceDictionary {
{ FontResources.DefaultButtonFontAttribute, FontAttributes.Bold },
{ FontResources.DefaultLabelFontSize,
Xamarin.Forms.Device.GetNamedSize(NamedSize.Small, typeof(Label)) },
{ StyleResources.DefaultLabelStyle, LABEL_STYLE }
}
(FontResources and StyleResources is a RESX file that contains the key name) Having
public static Style LABEL_STYLE = new Style(typeof(Label))
{
Setters = {
new Setter { Property = Label.FontSizeProperty, Value = new DynamicResource( FontResources.DefaultLabelFontSize )},
new Setter { Property = Label.FontAttributesProperty, Value = new DynamicResource( FontResources.DefaultLabelFontAttribute )},
}
};
The way I'm trying to do this is like this:
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.App">
<Application.Resources>
<ResourceDictionary>
<FontAttributes x:Key="DefaultLabelFontAttribute"></FontAttributes>
<FontSize x:Key="DefaultLabelFontSize"></FontSize>
<Style x:Key="DefaultLabelStyle" TargetType="Label">
<Setter Property="FontAttributes" Value="{DynamicResource DefaultLabelFontAttribute}"></Setter>
<Setter Property="FontSize" Value="{DynamicResource DefaultLabelFontSize}"></Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
But it seems that I'm not doing it the right way as there's no FontSize property similar to the FontAttribute. All I can see is FontSizeConverter. Also is there a way to call this code: Xamarin.Forms.Device.GetNamedSize(NamedSize.Small, typeof(Label)) to the Xaml?

Also is there a way to call this code: Xamarin.Forms.Device.GetNamedSize(NamedSize.Small, typeof(Label)) to the Xaml?
ResourceDictionary:
<ResourceDictionary>
<Style x:Key="Labelfont" TargetType="Label">
<Setter Property="FontSize" Value="Small" />
</Style>
</ResourceDictionary>
Style Usage:
Label Text="UsingSmallFont" Style="{StaticResource Labelfont}"/>

Related

in visual studio 2019, how to customise navigation bar in each view (not globally)

I want to customise navigation bar for one view (again, not globally, just for that one view). I have search on the internet and only found how to customise it globally from the app.xaml file.
I have tried to code as below in my view.xaml file
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor"
Value="{StaticResource blackColor}"/>
<Setter Property="BarTextColor"
Value="{StaticResource whiteColor}"/>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
but it does not work unlike when I stylise other item such as entries/buttons
Regarding Style if Key is not set to a value, then style is applied to all the objects of the TargetType.
In your App.Xaml, set a Style with x:Key
<Style TargetType="ContentPage" x:Key="specialPage">
<Setter Property="BackgroundColor" Value="Green"/>
</Style>
In your ContentPage page
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Style="{StaticResource Key=specialPage}"
As you can see this style is for ContentPage as NavigationApp is set only once for an Application you could set the property of NavigationBar in ContentPage Style.
So,
1) You can keep the NavigationPage static and use the static variable to change the NavigationPage Property
App.Xaml.cs
public static App CurrentApplication;
public NavigationPage AppNavigationPage;
public App()
{
InitializeComponent();
CurrentApplication = this;
this.AppNavigationPage = new NavigationPage(new MainPage());
MainPage = this.AppNavigationPage;
}
Page.Xaml.cs
public Page1()
{
InitializeComponent();
App.CurrentApplication.AppNavigationPage.BarBackgroundColor = Color.Red;
}
2) Use Dynamic resource for styling the NavigationPage
NavigationPage.TitleView
This tag will help you to customize your Navigation bar.

Xamarin Forms - how to select resource in C# from MergedDictionaries

Can someone show me the Linq query that would be used to select the AdjustmentsIcon style in the IconResources.xaml file below?
I know you can get to ...
Application.Current.Resources["key"]
but I am looking for a code efficient way to select out the style from the MergeDictionary using Linq.
App.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:font="clr-namespace:WP.Device.Resources"
xmlns:resources="clr-namespace:WP.Device.Resources"
x:Class="WP.Device.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<resources:IconResources />
<resources:ColorResources />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
IconResources.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:font="clr-namespace:WP.Device.Resources"
xmlns:resources="clr-namespace:WP.Device.Resources"
x:Class="WP.Device.Resources.IconResources">
<ResourceDictionary.MergedDictionaries>
<resources:ColorResources />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="Label" x:Key="AddNewIcon">
<Setter Property="FontSize" Value="30" />
</Style>
<Style TargetType="Label" x:Key="AdjustmentsIcon">
<Setter Property="FontSize" Value="40" />
</Style>
</ResourceDictionary>
UPDATE
I appreciate #pinedax's answer, but for me...
Application.Current.Resources["key"]
doesn't have the keys from the merged dictionaries. I was not able to formulate a Linq query to find my style, but I wrote the following that works...
public Style FindStyle(ResourceDictionary resourceDictionary, string key)
{
Style style = resourceDictionary.ContainsKey(key) ? resourceDictionary[key] as Style : null;
if (style == null)
{
foreach (var mergedDictionary in resourceDictionary.MergedDictionaries)
{
style = FindStyle(mergedDictionary, key);
if (style != null) break;
}
}
return style;
}
and is called with...
Style errorIcon = FindStyle(Application.Current.Resources, "AddNewIcon");
Application.Current.Resources.TryGetValue("key", out var result);
will also look in the merged dictionaries (as stated by #pinedax here).
I do encourage you to use the default way of fetching resources out of a ResourceDictionary as for me it is very efficient.
If you look at the ResourceDictionary source code (here) you will see there's an internal dictionary that holds all the resources keys, so when we do:
Application.Current.Resources["key"]
This is actually getting the value from that internal dictionary and dictionary lookup by key is very efficient.
But to answer your question, you should be able to get the values using Linq by using the SelectMany method on the MergeDictionaries property. Something like this:
var mergedDictionary = Application.Current.Resources.MergedDictionaries;
var resourceK = mergedDictionary.SelectMany(x => x)
.Where(v => v.Key == "Key")
.Select(t => t.Value)
.FirstOrDefault();
Hope this helps.-

Customize named font sizes depending on the screen-size

In a xamarin.forms app, how could I customize named font sizes depending on the screen-size for the default ones don't work for me?
mainScale.LabelFontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)) * 2.5;
I've hardcoded 2.5 because it looks better.
Could you please let me know how I could have these hardcoded ones changed to a dynamic factor in a cross-platform app?
This is a Idea to how to create sizes.
App.xaml.cs
public static double DisplayScreenWidth = 0f;
public static double DisplayScreenHeight = 0f;
public static double Size1 { get; private set; }
public static double Size2 { get; private set; }
public static double Size3 { get; private set; }
if(DisplayScreenHeight > 560)
{
Size1 = Device.GetNamedSize(NamedSize.Large, typeof(Label)) * 1.6;
}
else
{
Size1 = Device.GetNamedSize(NamedSize.Large, typeof(Label)) * 1.2;
}
Activity.cs
App.DisplayScreenWidth = (double)Resources.DisplayMetrics.WidthPixels / (double)Resources.DisplayMetrics.Density;
App.DisplayScreenHeight = (double)Resources.DisplayMetrics.HeightPixels / (double)Resources.DisplayMetrics.Density;
App.xaml
xmlns:local="clr-namespace:Mobile" >
<Style x:Key="baseStyle" TargetType="Label">
<Style.Triggers>
<Trigger TargetType="Label"
Property="FontAttributes"
Value="None">
<Setter Property="FontFamily" Value="OpenSans-Regular.ttf#Regular" />
</Trigger>
<Trigger TargetType="Label"
Property="FontAttributes"
Value="Bold">
<Setter Property="FontFamily" Value="OpenSans-Bold.ttf#Regular-Bold" />
</Trigger>
</Style.Triggers>
</Style>
<!-- TAMANHO DE FONTES -->
<Style x:Key="Size1" TargetType="Label" BasedOn="{StaticResource baseStyle}">
<Setter Property="FontSize" Value="{Binding Source={x:Static local:App.Size1}}"/>
</Style>
<Style x:Key="Size2" TargetType="Label" BasedOn="{StaticResource baseStyle}">
<Setter Property="FontSize" Value="{Binding Source={x:Static local:App.Size2}}"/>
</Style>
Home.xaml
<label Text="Hello from Xamarin Forms" Style="{StaticResource Size1}"/>
I have come across a cross-platform screen resolution solution given by Allan Ritchie GitHub link and the nuget package is Nuget link
In the shared .net standard library, in the respective ContentView, the below code works:
protected override void OnSizeAllocated(double width, double height)
{
// specific font adjustment code goes here
if (CrossDevice.Hardware.ScreenHeight > 600)
{
...
}
...
base.OnSizeAllocated(width, height); //must be called
}

Custom Renderer: Custom Renderer for rounded buttons

I am developing a cross-platform app using PCL Xamarin Forms Project. My app will run on ios, android, windows 10 and windows 8.1 desktops.
I want to make a custom renderer for button control in xamarin forms in which I can specify following properties from xaml page and from code behind also-
Border Color
Border Width
Border Radius
Background Color
Text Color
Text font size, color, attribute like bold.
Height and Width of Button
I have tried the normal button control of xamarin forms but in that border radius does not work in android and on hover button color changes in windows 10.
So how can I achieve this?
I using these properties on my app and for me works fine.
I am using these properties with "Styles".
Example:
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="BackgroundColor" Value="{DynamicResource Snow}"/>
<Setter Property="TextColor" Value="{DynamicResource LightBlue}" />
<Setter Property="BorderColor" Value="{DynamicResource LightBlue}"/>
<Setter Property="BorderRadius" Value="15"/>
<Setter Property="BorderWidth" Value="1"/>
<Setter Property="FontAttributes" Value="Bold" />
</Style>
My Button:
<Button Text="Login" Command="{Binding LoginCommand}" Style="{DynamicResource buttonStyle}" />
Xamarin Styles
In Android the RadiusProperty stops working only with AppCompat its a known issue
AppCompat
If you want to use a normal button and AppCompat at the same time you will need to inherit from Button and register a CustomRenderer.
[assembly: ExportRenderer(typeof(RoundButton), typeof(RoundButtonRenderer))]
namespace Project.Droid.Renderers
{
public class RoundButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
{
ButtonDrawable _backgroundDrawable;
Drawable _defaultDrawable;
bool _drawableEnabled;
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_backgroundDrawable != null)
{
_backgroundDrawable.Dispose();
_backgroundDrawable = null;
}
}
base.Dispose(disposing);
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (e.OldElement != null && _drawableEnabled)
{
_drawableEnabled = false;
_backgroundDrawable.Reset();
_backgroundDrawable = null;
}
UpdateDrawable();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (_drawableEnabled &&
(e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderRadiusProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Button.BorderWidthProperty.PropertyName))
{
_backgroundDrawable.Reset();
Control.Invalidate();
}
base.OnElementPropertyChanged(sender, e);
}
private void UpdateDrawable()
{
if (Element.BackgroundColor == Color.Default)
{
if (!_drawableEnabled)
return;
if (_defaultDrawable != null)
Control.SetBackground(_defaultDrawable);
_drawableEnabled = false;
}
else
{
if (_backgroundDrawable == null)
_backgroundDrawable = new ButtonDrawable();
_backgroundDrawable.Button = Element;
if (_drawableEnabled)
return;
if (_defaultDrawable == null)
_defaultDrawable = Control.Background;
Control.SetBackground(_backgroundDrawable.GetDrawable());
_drawableEnabled = true;
}
Control.Invalidate();
}
}
public class ButtonDrawable : IDisposable
{
object _backgroundDrawable;
PropertyInfo ButtonProperty;
public Xamarin.Forms.Button Button
{
get
{
return (Xamarin.Forms.Button)ButtonProperty.GetMethod.Invoke(_backgroundDrawable, null);
}
set
{
ButtonProperty.SetMethod.Invoke(_backgroundDrawable, new object[] { value });
}
}
public ButtonDrawable()
{
_backgroundDrawable = typeof(Xamarin.Forms.Platform.Android.ButtonRenderer).Assembly.CreateInstance("Xamarin.Forms.Platform.Android.ButtonDrawable");
this.ResetMethod = _backgroundDrawable.GetType().GetMethod("Reset", BindingFlags.Instance | BindingFlags.Public);
this.DisposeMethod = _backgroundDrawable.GetType().GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
this.ButtonProperty = _backgroundDrawable.GetType().GetProperty("Button", BindingFlags.Instance | BindingFlags.Public);
}
MethodInfo ResetMethod;
public void Reset()
{
ResetMethod.Invoke(_backgroundDrawable, null);
}
MethodInfo DisposeMethod;
public void Dispose()
{
DisposeMethod.Invoke(_backgroundDrawable, null);
}
public Android.Graphics.Drawables.Drawable GetDrawable()
{
return _backgroundDrawable as Android.Graphics.Drawables.Drawable;
}
}
}
Without AppCompat
if you want to remove AppCompat you must do two things
Your MainActivity must inherit now from global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
and your style usually in resources/values/styles.xml must inherit from a non-AppCompat style like android:Theme.Material
<resources>
<!-- inherit from the material theme -->
<style name="AppTheme" parent="android:Theme.Material">
<!-- Main theme colors -->
<!-- your app branding color for the app bar -->
<item name="android:colorPrimary">#color/primary</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="android:colorPrimaryDark">#color/primary_dark</item>
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">#color/accent</item>
</style>
</resources>
Create a style in Content Page resource and and add this style in button.
CornerRadius is must be half of HeightRequest and WidthRequest.
This is for Xamarin.Forms >= 3.4. Now BorderRadius convert into CornerRadius.
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="myRoundbutton" TargetType="Button">
<Setter Property="BackgroundColor" Value="Green"/>
<Setter Property="TextColor" Value="White" />
<Setter Property="BorderColor" Value="Blue"/>
<Setter Property="CornerRadius" Value="35"/>
<Setter Property="HeightRequest" Value="70" />
<Setter Property="WidthRequest" Value="70"/>
<Setter Property="BorderWidth" Value="2"/>
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout HorizontalOptions="Fill"
VerticalOptions="Fill">
<Button Image="myBtn3.png"
Command="{Binding LoginCommand}"
Style="{DynamicResource myRoundbutton}" />
</StackLayout>
</ContentPage.Content>

Apply style to control in custom renderer

I want to apply a style to a control. This is the style
<Application.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="BackgroundColor" Color="Yellow" />
<Style TargetType="Button" x:Name="myNewButtonStyle">
<Setter Property="Background" Value="{StaticResource BackgroundColor}" />
</Style>
</ResourceDictionary>
</Application.Resources>
, which can be found in App.xaml (UWP project). And here is the custom renderer:
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (this.Element != null)
{
var style = Windows.UI.Xaml.Application.Current.Resources["myNewButtonStyle"] as Windows.UI.Xaml.Style;
this.Control.Style = style;
}
}
The idea is based on this answer. But the style isn't applied. Setting the background color in code does work:
this.Control.BackgroundColor = new SolidColorBrush(Windows.UI.Colors.Yellow);
How can I apply a style to a control in a custom renderer?
I've filled a bug report. It should be fixed in one of the upcoming releases (> XF 2.3.3.166-pre4).

Resources