How to Set a Custom Font Family in the Xamarin ActionBar Title? - xaml

As in title. I found the idea how to do this here Custom Fonts in Xamarin.Forms NavigationBar + ActionBar that tells to define this in style.xml file but I'm not able to get the custom font family.
So my style look like this right now:
<style name="Toolbar.TitleText" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
<!--set your custom font properties-->
<item name="android:textSize">18sp</item>
<item name="android:fontFamily">HelveticaNeue Medium.ttf</item>
<item name="android:textColor">#android:color/white</item>

You can create a custom renderer in android for this purpose. The renderer simply changes the typeface of your navigation bar using the resource defined in your android project. You can use the following renderer in android:
[assembly: ExportRenderer(typeof(NavigationPage), typeof(AndroidNavigationRenderer))]
namespace Xamarin.Droid.DependencyServices
{
public class AndroidNavigationRenderer : NavigationPageRenderer
{
private Android.Support.V7.Widget.Toolbar toolbar;
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
if (child.GetType() == typeof(Android.Support.V7.Widget.Toolbar))
{
toolbar = (Android.Support.V7.Widget.Toolbar)child;
toolbar.ChildViewAdded += Toolbar_ChildViewAdded;
}
}
private void Toolbar_ChildViewAdded(object sender, ChildViewAddedEventArgs e)
{
var view = e.Child.GetType();
if (e.Child.GetType() == typeof(Android.Support.V7.Widget.AppCompatTextView))
{
var textView = (Android.Support.V7.Widget.AppCompatTextView)e.Child;
textView.Typeface = Typeface.CreateFromAsset(this.Context.Assets, "fonts/QuicksandRegular.ttf");
toolbar.ChildViewAdded -= Toolbar_ChildViewAdded;
}
}
}
}
For UWP, you can define a custom style in your app.xaml to override the default style of your title bar. You can use the following code in UWP:
<Style x:Key="TitleTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontStyle" Value="Normal"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="FontFamily" Value="Assets/Fonts/QuicksandRegular.ttf#Quicksand"/>
<Setter Property="Padding" Value="10"/>
</Style>
Simply change the font family to the font family of your choice.

Related

Xamarin forms IOS Buttons looking distorted

I have the following XAML code below :
<StackLayout
Grid.Row="2"
Orientation="Horizontal"
VerticalOptions="End"
Margin="0,0,0,20"
Spacing="28">
<Button
x:Name="SignInButton"
Visual="Material"
Padding="5"
Margin="10,0,0,0"
Style="{DynamicResource ButtonSecondary}"
HorizontalOptions="FillAndExpand"
Text="Sign In"
Clicked="SignInButton_Clicked"/>
<Button
x:Name="JoinUsButton"
Visual="Material"
Padding="5"
Margin="0,0,10,0"
Style="{DynamicResource ButtonPrimary}"
HorizontalOptions="FillAndExpand"
VerticalOptions="End"
Text="Join Us"
Clicked="JoinUsButton_Clicked"/>
</StackLayout>
The dynamic resources currently stored in the App.xaml file are as follows :
<Style x:Name="ButtonSecondary" x:Key="ButtonSecondary" TargetType="Button" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{DynamicResource SecondaryColor}" />
<Setter Property="TextColor"
Value="{DynamicResource PrimaryTextColor}" />
<Setter Property="BorderWidth"
Value="1" />
<Setter Property="BorderColor"
Value="{DynamicResource SecondaryBorderColor}" />
<Setter Property="CornerRadius"
Value="50" />
</Style>
However, when I run the app on iOS the buttons look like the image below.
However, on the android device, the buttons look like the image below :
Cauuse : In iOS , if you want to achieve the effect like the above image which you get in Android , you need to set the CornerRadius as half of its HeightRequest .
Solution
Option 1
If the size of the button is always a fixed value , you just need to set the HeightRequest in the style
<Style x:Name="ButtonSecondary" x:Key="ButtonSecondary" TargetType="Button" ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="{DynamicResource SecondaryColor}" />
<Setter Property="TextColor"
Value="{DynamicResource PrimaryTextColor}" />
<Setter Property="BorderWidth"
Value="1" />
<Setter Property="BorderColor"
Value="{DynamicResource SecondaryBorderColor}" />
<Setter Property="CornerRadius"
Value="25" />
<Setter Property="HeightRequest"
Value="50" /> // double of CornerRadius
</Style>
Option 2 :
If the size of Button will change in runtime , you could use Custom Renderer to set the CornerRadius in iOS platform .
in Forms
create a custom button
public class MyButton:Button
{
}
in iOS
using Foundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using App6;
using App6.iOS;
using System.ComponentModel;
[assembly:ExportRenderer(typeof(MyButton),typeof(MyButtonRenderer))]
namespace App6.iOS
{
public class MyButtonRenderer:ButtonRenderer
{
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if(e.PropertyName=="Height")
{
var height = Element.Height;
Control.Layer.MasksToBounds = true;
Control.Layer.BorderColor = UIColor.Black.CGColor;
Control.Layer.CornerRadius = (nfloat)(height / 2.0);
Control.Layer.BorderWidth = (nfloat)0.5;
}
}
}
}
in xaml
<local:MyButton
x:Name="SignInButton"
Visual="Material"
Padding="5"
Margin="10,0,0,0"
Style="{DynamicResource ButtonSecondary}"
HorizontalOptions="FillAndExpand"
Text="Sign In"
/>
While I can't see the exact issue you are seeing with the distortion I do see an inconsistency between platforms. This ultimately comes down to how the individual platforms render the CornerRadius property. Android will limit it to what is visibly sensible (basically half the height/width, whichever is smaller) whereas iOS will just do as you ask.
This image shows on the left what I currently see, the middle is my second solution and the right is my first solution.
My possible solutions are:
Attach a Behavior
public class RoundCornerBehavior : Behavior<Button>
{
protected override void OnAttachedTo(Button button)
{
button.SizeChanged += OnSizeChanged;
base.OnAttachedTo(button);
}
protected override void OnDetachingFrom(Button button)
{
button.SizeChanged -= OnSizeChanged;
base.OnDetachingFrom(button);
}
private void OnSizeChanged(object sender, EventArgs e)
{
var button = (Button) sender;
button.CornerRadius = (int)Math.Min(button.Width, button.Height) / 2;
}
public static readonly BindableProperty AttachBehaviorProperty =
BindableProperty.CreateAttached("AttachBehavior", typeof(bool), typeof(RoundCornerBehavior), false, propertyChanged: OnAttachBehaviorChanged);
public static bool GetAttachBehavior(BindableObject view)
{
return (bool)view.GetValue(AttachBehaviorProperty);
}
public static void SetAttachBehavior(BindableObject view, bool value)
{
view.SetValue(AttachBehaviorProperty, value);
}
static void OnAttachBehaviorChanged(BindableObject view, object oldValue, object newValue)
{
if (!(view is Button button))
{
return;
}
var attachBehavior = (bool)newValue;
if (attachBehavior)
{
button.Behaviors.Add(new RoundCornerBehavior());
}
else
{
var toRemove = button.Behaviors.FirstOrDefault(b => b is RoundCornerBehavior);
if (toRemove != null)
{
button.Behaviors.Remove(toRemove);
}
}
}
}
Then simply attach in your style:
<Setter Property="roundButton:RoundCornerBehavior.AttachBehavior" Value="true" />
I would suggest writing some kind of Behavior to provide the sensible CornerRadius which would essentially take the Width and Height properties of the control and simply set the CornerRadius to half the smallest value. I will see if I can knock something up to provide a concrete example shortly.
The nice result of this approach will allow you to continue to define the controls as you were previously and keep the logic self contained in the attached behavior.
Sub class button
An alternative would be to sub class Button and created your own RoundedButton that could do the same as the Behavior approach. Then
public class RoundedButton : Button
{
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
this.CornerRadius = (int)Math.Min(width, height) / 2;
}
}

uwp define eventriggerbehavior inside style

I'm currently stuck with a problem. I want to declare a eventriggerbehavior for all my listviews. this is my code:
<Style TargetType="ListView">
<Setter Property="ItemTemplate" Value="{StaticResource itemShowTemplate}" />
<i:Interaction.Behaviors>
<Interactions:EventTriggerBehavior EventName="ItemClicked">
<Interactions:InvokeCommandAction Command="{Binding ShowItemClickedCommand}" />
</Interactions:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Style>
the problem I have now is that EventTriggerBehavior is looking for the event on Style and not the targettype of Listview. And the only property left to set on EventTriggerBehavior is SourceObject. But I don't want this behavior on 1 listview, I want it on al my listviews.
Is there a way todo this?
My first idea was that it could work this way:
<Style TargetType="Button">
<Setter Property="i:Interaction.Behaviors">
<Setter.Value>
<i:BehaviorCollection>
<core:EventTriggerBehavior EventName="Click">
<core:InvokeCommandAction Command="{Binding TestCommand}" />
</core:EventTriggerBehavior>
</i:BehaviorCollection>
</Setter.Value>
</Setter>
</Style>
But unfortunately this works only for the first control which gets the behavior attached. The reason is that the value is constructed just once and the AssociatedObject property of the BehaviorCollection is set to the first control.
I have then come over this solution - How to add a Blend Behavior in a Style Setter .
The idea is to create an attached property that manually assigns the behavior to the control.
Based on this I suggest you do it like this:
public static class ListViewBehaviorAttacher
{
public static readonly DependencyProperty IsAttachedProperty = DependencyProperty.RegisterAttached(
"IsAttached", typeof(bool), typeof(ListViewBehaviorAttacher), new PropertyMetadata(default(bool), IsAttachedChanged));
private static void IsAttachedChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var listView = (ListView)dependencyObject;
//create the binding
BehaviorCollection collection = new BehaviorCollection();
var eventTrigger = new EventTriggerBehavior() { EventName = "ItemClick" };
var invokeCommandAction = new InvokeCommandAction();
//binding to command
BindingOperations.SetBinding(
invokeCommandAction,
InvokeCommandAction.CommandProperty,
new Binding() { Path = new PropertyPath("ShowItemClickedCommand"), Source = listView.DataContext });
eventTrigger.Actions.Add(invokeCommandAction);
collection.Add(eventTrigger);
listView.SetValue(Interaction.BehaviorsProperty, collection);
}
public static void SetIsAttached(DependencyObject element, bool value)
{
element.SetValue(IsAttachedProperty, value);
}
public static bool GetIsAttached(DependencyObject element)
{
return (bool)element.GetValue(IsAttachedProperty);
}
}
And then in the style attach it like this:
<Style TargetType="ListView">
<Setter Property="SelectionMode" Value="None"></Setter>
<Setter Property="IsItemClickEnabled" Value="True" />
<Setter Property="local:ListViewBehaviorAttacher.IsAttached" Value="True" />
</Style>

ToogleMenuFlyout and MenuFlyoutPresenterStyle Set Width - Windows 10 Mobile

I need the items in a ToogleMenuFlyout occupy the full width of the screen.
But I'm not solve the problem.
I'm trying to put the width of my Grid (Grid Main page) but I do not get to do in code-behind.
I am applying a style to MenuFlyoutPresenterStyle but also not to give.
my code is:
AppBarButton x:Name="FiltersPhone" Icon="Filter" Label="Names">
<AppBarButton.Flyout>
<MenuFlyout>
<MenuFlyout.MenuFlyoutPresenterStyle>
<Style TargetType="MenuFlyoutPresenter">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Margin" Value="0,4,0,0"/>
</Style>
</MenuFlyout.MenuFlyoutPresenterStyle>
<ToggleMenuFlyoutItem x:Name="FlyoutItemDate" Text="Today" Tag="Date"
IsChecked="True/>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
Apply the following should help [Updated to support landscape]:
Note that: this is still not a perfect solution to meet all your requirement. I am just trying to let you understand the MenuFlyoutPresenter's Maxwidth and the ToggleMenuFlyoutItem's width properties are the key to impelement what you want.
Set x:Name = "rootGrid" to page's root grid
In code-behind, implement the following:
public Page2()
{
this.InitializeComponent();
this.Loaded += Page2_Loaded;
}
private void Page2_Loaded(object sender, RoutedEventArgs e)
{
FlyoutItemDate.Width = rootGrid.ActualWidth;
DisplayInformation di = DisplayInformation.GetForCurrentView();
di.OrientationChanged += Di_OrientationChanged;
}
private void Di_OrientationChanged(DisplayInformation sender, object args)
{
if (sender.CurrentOrientation == DisplayOrientations.Portrait)
{
FlyoutItemDate.Width = rootGrid.ActualWidth;
}
else if(sender.CurrentOrientation == DisplayOrientations.Landscape)
{
FlyoutItemDate.Width = rootGrid.ActualHeight;
}
}
Increase maxwidth of MenuFlyoutPresenter to larger one(like 1000)
<Style TargetType="MenuFlyoutPresenter">
<Setter Property="Background" Value="Red"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Margin" Value="0,4,0,0"/>
<Setter Property="MaxWidth" Value="1000"/>
</Style>
Here is the result and I make the background to red to make it clear:

XAML and Silverlight: Applying style to subclass fails

I have created a subclass of TextBox
public class MyAwesomeTextBox : TextBox { ... }
and have set the color of all TextBoxes to be red
<UserControl>
<UserControl.Resources>
<Style TargetType="TextBox">
<Setter Property="Background" Value="Red" />
</Style>
</UserControl.Resources>
<TextBox ... />
<xyz:MyAwesomeTextBox ... />
</UserControl>
It works for all TextBoxes but not for MyAwesomeTextBoxes.
Please tell me what is wrong.
I bet you set the DefaultStyleKey property to typeof(MyAwesomeTextBox) and now the framework will only apply a style with the specialized stylekey.
See the documentation, I extracted the following part:
If you do not set the DefaultStyleKey, the default style for the base class is used. For example, if a control called NewButton inherits from Button, to use a new default Style, set DefaultStyleKey to the type, NewButton. If you do not set DefaultStyleKey, the Style for Button is used.
So what can you do now? You can either remove the defaultStyleKey (but that means the TextBox style will be applied everywhere in your application and you cannot have you AwesomeControlTemplate applied to it by default, so I think this is not what you should do now) or you can add a derived style to your resources:
<UserControl.Resources>
<Style TargetType="TextBox" x:Key="BaseStyle">
<Setter Property="Background" Value="Red" />
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}">
<Style TargetType="MyAwesomeTextBox" BasedOn="{StaticResource BaseStyle}">
</UserControl.Resources>

How can I override a Foreground property with a Style after initialization?

So I have a TextBlock-element in my Windows 8 app which I override the foreground color of like this:
TestTextBlock.Foreground = new SolidColorBrush(Color.FromArgb(255,255,0,0));
I would like to override this color at a later point using a style with a different Foreground-color. Style:
<Style TargetType="TextBlock" x:Key="MyStyle">
<Setter Property="Foreground" Value="Yellow"/>
</Style>
Override:
TestTextBlock.Style = (Style) App.Current.Resources["MyStyle"];
Now this works if I don't initialize the Foreground-property first. It seems as if Foreground has precedence over Style. Thing is this is a simplified example and I can't remove the code line setting the Foreground-property.
Any other way of working around this? I tried setting Foreground = null, but that resulted in invisible text.
You can set your default color however you want, then personally I run a ColorAnimation at it via Storyboard like;
<Storyboard x:Key="ChangeThatForegroundColor">
<ColorAnimation Duration="0"
Storyboard.TargetName="YourTextBlockName"
Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)"
To="Yellow" />
</Storyboard>
and you can fire it off with the BeginStoryboard method. Hope this helps.
hope this help :it works for me
<TextBlock x:Name="TestTextBlock" Text="Hello world"/>
1)override SolidColorBrush with solidcolorbrush only
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
TestTextBlock.Foreground = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
TestTextBlock.Foreground = new SolidColorBrush(Colors.Yellow);
}
2)override style with style only
<Style x:Key="MyStyle" TargetType="TextBlock" >
<Setter Property="Foreground" Value="Red"/>
</Style>
<Style x:Key="MyStyle1" TargetType="TextBlock" >
<Setter Property="Foreground" Value="Yellow"/>
</Style>
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
TestTextBlock.Style = (Style)App.Current.Resources["MyStyle"];
TestTextBlock.Style = (Style)App.Current.Resources["MyStyle1"];
}