1

I want to set the fontFamily of the Toolbar's texts, Buttons, TextViews and for all the text of the Xamarin.Andrid application in general. How do I do that in a single place? I tried putting the following in the Base application theme in styles.xml :

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    .....
    <item name="fontFamily">@drawable/Exo2_ExtraBold</item>
    .....
</style>

But it only changed the fontFamily of the MainActivity, I guess it's because only that activity has Theme = "@style/AppTheme" attribute above it. If I put that attribute above the rest of the activities I guess it will also work, but isn't there an easier way to achieve all the app to have one fontFamily setting it in a single place of the application? And also I put the .otf file in the drawables folder I tried putting it in the font folder I created manually but it gave me an error when trying to rebuild the solution. So I'd like to know how can I fix that also, to put the .oft in the correct folder.

Montoolivo
  • 137
  • 2
  • 3
  • 15

3 Answers3

2

The easiest way to use custom font in android is using Calligraphy, for Xamarin you can use CallygraphyXamarin.

  1. Copy your custom font, e.g: my-custom-font.ttf, to fonts directory, inside assets directory.
  2. Add CallygraphyXamarin nuget package Install-Package CallygraphyXamarin

  3. Create a class, e.g: Startup and add following content to it:

[Application]
public class Startup : Application
{   
    public Startup(IntPtr javaReference, JniHandleOwnership transfer)
        : base(javaReference, transfer) { }

    public override void OnCreate()
    {
        base.OnCreate();

        CalligraphyConfig.InitDefault(
            new CalligraphyConfig.Builder()
                .SetDefaultFontPath("fonts/my-custom-font.ttf")
                .SetFontAttrId(Resource.Attribute.fontPath)
                .Build()
        );      
    }
}
  1. In your Activities add following code and you are good to go.
protected override void AttachBaseContext(Context context)
{
    base.AttachBaseContext(Calligraphy.CalligraphyContextWrapper.Wrap(context));
}

You can create a base activity to avoid adding above code to each activity.

Update:

In order to change the toolbar's font and if you don't want to add Textview as its title, you should add following style to style.xml

<style name="ToolbarTheme" parent="@style/ThemeOverlay.AppCompat.ActionBar">
    <item name="fontPath">fonts/custom-font.ttf</item>
</style>

And apply this style to toolbar like this:

<android.support.v7.widget.Toolbar
    ...
    android:theme="@style/ToolbarTheme"/>

Related github issue

Mehdi Dehghani
  • 10,970
  • 6
  • 59
  • 64
  • In `AttachBaseContext` method `Calligraphy.CalligraphyContextWrapper.Wrap(context)` wasn't recognized as a method so I put `Calligraphy.Xamarin.CalligraphyContextWrapper.Wrap(context)` instead. When I ran the application I got the following error at the `SetContentView(Resource.Layout.MainActivity)` line of the `MainActivity`(which is my main launcher): `System.InvalidCastException: Specified cast is not valid.` – Montoolivo Jan 05 '20 at 08:03
  • I posted my `MainActivity.cs` as an answer to my question. – Montoolivo Jan 06 '20 at 09:02
  • All my activities except the `MainActivity` have `Toolbar` with title on it. But its `fontFamily` didn't change. What do I do to change it? – Montoolivo Jan 07 '20 at 08:09
  • Yes, the new package works. I haven't applied any styles to the `Toolbar` here it is: `` neither in `styles.xml` – Montoolivo Jan 07 '20 at 08:37
  • I have 3 questions. Does `Startup` class serve only for setting the `fontFamily` for the entire application, or I can put any initialization logic in it? My second question is, if I put `AttachBaseContext` method in a `BaseActivity` , what comment do I put above it, what does it do? My third question , my `MainActivity` inherits from `AppCompatActivity` all the other activities inherit from `Activity`. If I create `BaseActivity` that inherits from `AppCompatActivity` and make `MainActivity` and the rest of the activities inherit `BaseActivity`, will this be a problem? – Montoolivo Jan 07 '20 at 11:27
  • 1. [Understanding the Android Application Class](https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class). 2. [What is the role of attachBaseContext?](https://stackoverflow.com/q/51759985/3367974). 3. No, there will be no problem (as far as I know), but I think you should use `AppCompatActivity` if you use support libraries, there is no benefit in using `Activity` compare to `AppCompatActivity`, see [Activity, AppCompatActivity, FragmentActivity, and ActionBarActivity: When to Use Which?](https://stackoverflow.com/q/31297246/3367974). – Mehdi Dehghani Jan 07 '20 at 14:42
0

When we create a new Activity , the super class of it is Activity in default . So we should change it to AppCompatActivity manually . And add the line Theme = "@style/AppTheme"

using Android.Support.V7.App;
[Activity(Label = "Activity1", Theme = "@style/AppTheme")]
public class Activity1 : AppCompatActivity
Lucas Zhang
  • 18,630
  • 3
  • 12
  • 22
0

Here is my MainActivity :

[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true, ScreenOrientation = ScreenOrientation.Portrait)]
public class MainActivity : AppCompatActivity
{
    Button informationBtn;
    ImageButton congressImageBtn;
    ImageButton exhibitionAreaImageBtn;
    ImageButton facebookImageBtn;
    ImageButton twitterImageBtn;
    ImageButton linkedinImageBtn;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        SetContentView(Resource.Layout.MainActivity);

        FindViews();

        BindClickEvents();

    }

    /// <summary>
    /// Method to find the views
    /// </summary>
    private void FindViews()
    {
        informationBtn = FindViewById<Button>(Resource.Id.informationBtn);
        congressImageBtn = FindViewById<ImageButton>(Resource.Id.congressImageBtn);
        exhibitionAreaImageBtn = FindViewById<ImageButton>(Resource.Id.exhibitionAreaImageBtn);
        facebookImageBtn = FindViewById<ImageButton>(Resource.Id.facebookImageBtn);
        twitterImageBtn = FindViewById<ImageButton>(Resource.Id.twitterImageBtn);
        linkedinImageBtn = FindViewById<ImageButton>(Resource.Id.linkedinImageBtn);
    }

    /// <summary>
    /// Method to bind the click events
    /// </summary>
    private void BindClickEvents()
    {
        informationBtn.Click += delegate
        {
            StartActivity(typeof(ContactInformationActivity));
            Finish();
        };

        congressImageBtn.Click += delegate
        {
            StartActivity(typeof(CongressActivity));
            Finish();
        };

        exhibitionAreaImageBtn.Click += delegate
        {
            StartActivity(typeof(ExhibitionAreaActivity));
            Finish();
        };

        facebookImageBtn.Click += delegate
        {
            var uri = Android.Net.Uri.Parse("https://www.facebook.com/");
            var intent = new Intent(Intent.ActionView, uri);
            StartActivity(intent);
        };

        twitterImageBtn.Click += delegate
        {
            var uri = Android.Net.Uri.Parse("https://twitter.com/");
            var intent = new Intent(Intent.ActionView, uri);
            StartActivity(intent);
        };

        linkedinImageBtn.Click += delegate
        {
            var uri = Android.Net.Uri.Parse("https://www.linkedin.com/");
            var intent = new Intent(Intent.ActionView, uri);
            StartActivity(intent);
        };
    }

    protected override void AttachBaseContext(Context context)
    {
        base.AttachBaseContext(Calligraphy.Xamarin.CalligraphyContextWrapper.Wrap(context));
    }

}
Montoolivo
  • 137
  • 2
  • 3
  • 15
  • Yes, it's the same. The only difference is that I put `fonts/Exo2_ThinItalic.otf` instead of `fonts/my-custom-font.ttf`. This is the only difference. – Montoolivo Jan 06 '20 at 09:14