Blog Post

One of the very cool things about Android programming with Xamarin is that anything that can be implemented for Android with Java can also be implemented with C#.

For example, say the designer on your project designs an activity with a quick return toolbar… Since this is possible to do on any modern version of Android with the Android AppCompat Library in Java, it should be just as easy to do in a Xamarin application with C#.

Unless you are using a framework on top of Xamarin Android. Then all bets are off.

This post shows the problems I encountered with implementing a quick return toolbar with Xamarin Android and the latest stable version (until two weeks ago) of MvvmCross - v3.5.1.

AppCompat

I’ve posted a sample project on GitHub so that you can follow along at home. I’ve created a branch for each step in the process of implementing a quick return toolbar in an app. We’ll start on branch 1-before-appcompat.

When I compile and start the app, you can see that it has a typical Holo Light theme:

Holo Light theme

And if you tap on a post, you see the old Holo home as up indicator:

Holo Light theme

We wouldn’t easily be able to manipulate the position of this toolbar. That behavior is not natively supported before Android Material Design. However, we can add Material Design to pre-Lollipop Android versions by using AppCompat v21+.

Add AppCompat Nuget

The first step to getting a quick return toolbar is to get the app displaying a standard AppCompat toolbar, then we’ll dig deeper.

There is a Xamarin wrapper for AppCompat and Xamarin are extremely good at keeping this up to date. They usually release a new wrapper within a day or two of it being released by Android.

To add AppCompat to your project, add the following NuGet package: Xamarin.Android.Support.v7.AppCompat

AppCompat NuGet

Set Application Theme

By adding AppCompat to our app, we’re basically compiling all the Material Design goodness that is built into Android Lollipop directly into our app. But we haven’t told our app to use it yet…

To use the AppCompat theme, we need to modify our application theme. In my app, the theme is defined in /Resources/values/Theme.xml

<resources>
    <style name="MyTheme" parent="MyTheme.Base">
    </style>
<!--<style name="MyTheme.Base" parent="android:Theme.Holo.Light">-->
    <style name="MyTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>
    </style>
</resources>

I’ve also definied the Material Design color palette in /Resources/values/Colors.xml, but you can put the colors inline if you want.

OK, let’s start the application and see how the main activity looks:

After Adding AppCompat

Now there’s no toolbar at all!

Fetch the branch 2-appcompat-darkactionbar to have a look for yourself.

The reason for this is that the Activity class doesn’t know anything about AppCompat. The easiest way to make your activity AppCompat aware is to derive your activity from AppCompatActivity, as described by James Montemagno.

Derive From AppCompatActivity

This is where we meet our first real challenge with MvvmCross. MvvmCross 3.5.1 was in beta for 3 months and released just a few days after AppCompatActivity was born. So that version of MvvmCross doesn’t know about AppCompatActivity.

Using MvvmCross, you typically derive your activity from MvxActivity and that has the following heirarchy:

MvxActivity > MvxEventSourceActivity > Activity

If you actually decompile the code for MvxActivity and MvxEventSourceActivity, they’re not that complicated. They’re basically small wrappers around Activity that provide some basic services to the MvvmCross.

When I looked at the code I thought I could just copy this code and derive my class from AppCompatActivity rather than Activity. Essentially create a heirarchy like this:

MvxAppCompatActivity > MvxAppCompatEventSourceActivity > AppCompatActivity

It’s worth noting at this point that there was an alpha version of MvvmCross v3.5.2 where this had been implemented. I really didn’t fancy updating my existing production app to an alpha version of MvvmCross however. It was just too risky…

In the end, v3.5.2 alpha was never released as stable and formed the basis for MvvmCross v4.0 which was released as stable 8 months later!

So I copied the code for MvxAppCompatActivity and MvxAppCompat. You can see this code in this commit of branch 3-mvxappcompatactivity.

The next step was to change my activities to derive from the new class:

[Activity(MainLauncher=true)]
public class PostsView : MvxAppCompatActivity<PostsViewModel> // : MvxActivity<PostsViewModel>
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        SetContentView(Resource.Layout.View_Posts);
    }
}

Let’s run the app now to see if I get a toolbar.

Here’s the launch activity:

After Deriving From MvxAppCompatActivity

And if you tap on a post:

After Deriving From MvxAppCompatActivity

Perfect! I’ve got a nice AppCompat toolbar in my app’s theme color, and on the post page I’ve got a nice Material Design style back button. All thanks to my AppCompat theme. This is too easy!

Manually Include the Toolbar

This toolbar is automatically added to each activity - I don’t have any control over how this toolbar is placed.

If I want to make this a quick return toolbar, the next step is to include the toolbar manually in my layout. Then I will be able to manipulate it.

The first step is to disable the automatic toolbar in my theme:

<resources>
    <style name="MyTheme" parent="MyTheme.Base">
    </style>
<!--<style name="MyTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">-->
    <style name="MyTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>
        <item name="windowActionBar">false</item>
        <item name="android:windowNoTitle">true</item>
    </style>
</resources>

By setting the theme to NoActionBar, the toolbar won’t automatically be added to my activities.

Next, I create a layout called /Resources/layout/toolbar.xml which will be my toolbar:

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

The important bit here is that I set the theme of the toolbar to ThemeOverlay.AppCompat.Dark.ActionBar. Notice how this overlay matches with the original theme I used in the previous section Theme.AppCompat.Light.DarkActionBar.

DarkActionBar indicates that it is a dark colored toolbar with white text.

Next, include the toolbar layout in your activity layout files:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <include layout="@layout/toolbar" />
    <Mvx.MvxListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/listPosts"
        local:MvxBind="ItemsSource Posts; ItemClick ShowPostCommand"
        local:MvxItemTemplate="@layout/item_post" />
</LinearLayout>

Finally, we need to ask AppCompatActivity to make the toolbar appear as an actionbar to the activity so that it can be manipulated with legacy code:

[Activity(MainLauncher=true)]
public class PostsView : MvxAppCompatActivity<PostsViewModel>
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        SetContentView(Resource.Layout.View_Posts);

        var toolbar = FindViewById<Toolbar> (Resource.Id.toolbar);

        SetSupportActionBar (toolbar);
    }
}

You can see the full code in this commit of branch 4-toolbar-include.

Let’s start up the app and see how it looks. Heres the launch activity:

After Deriving From MvxAppCompatActivity

and here’s the post activity:

After Deriving From MvxAppCompatActivity

But wait, something’s wrong!

The text is black now… It’s supposed to be white and it was white when we used the DarkActionBar theme before.

Note: if you try this at home, this behavior happens on Android KitKat and below. On Android Lollipop it looks fine.

Options

When I first attempted this, I thought that I might have incorrectly specified the style of the toolbar.

I spent a day looking through the AppCompat styles on GitHub and attempting to change the text color with various attributes. I was unable to fix the text color.

I wasn’t sure if this was a problem with my implementation of the toolbar, or if it had something to do with my MvxAppCompatActivity hack.

So I created a new Xamarin Android application without MvvmCross showing an activity with my toolbar implementation. And it worked - the toolbar text was white!

I read through the issues and code at the MvvmCross GitHub repo and I learned that MvvmCross intercepts Android view inflation to do some custom stuff. This is most likely why the included toolbar was not being styled as expected.

My options were as follows:

  1. Upgrade to v3.5.2 alpha

  2. Learn the internals of MvvmCross with the intention of trying to fix the issue

  3. Give up for now

Option 1 was risky for our application that was already in production.

Option 2 was going to take some time. I had already spent a couple of days on this. Should we invest more time on a quick return toolbar even though there was no guarantee of finding a work around?

Option 3 meant going back to the designer and stating that although a quick return toolbar is easy to implement in a standard Android application, it’s more difficult to do in our application because of a framework we are using.

On Frameworks

This is not a unique problem to MvvmCross. It took Xamarin Forms a long time before it supported using an AppCompat toolbar in that framework.

I know because I worked on a Xamarin Forms project where the designer wanted a Material Design look and feel.

It is also not a criticism of MvvmCross in particular. It is an open source project and the code is published on GitHub. I could have spent more time investigating the problem, writing a fix, and even submit a pull request for everyone else to use.

The above experience is why hesitate before picking a framework like MvvmCross or Xamarin Forms etc when starting a new project.

These frameworks can increase productivity and result in better quality code. But they may also restrict your options when you’re trying to implement fairly standard features.

My personal opinion is that AppCompat is a 100% requirement for almost every Android project!

MvvmCross 4

MvvmCross v4.0 was released about 2 weeks ago.

They’ve added official support for the AppCompat library in the package MvvmCross.Droid.Support.V7.AppCompat. I was curious to see whether upgrading the app would fix our AppCompat woes.

The upgrade was mostly painless - there is a guide here.

The biggest change is that the namespaces for most classes have changed, which in turn requires me to touch most files of my project too.

Additionally, this test application kept crashing on startup. I finally realized that, for some reason, MvvmCross 4 requires a splash screen or the app will crash on start.

I’m not sure if that’s a bug or an intentional change from the previous version, but it did take me some time to figure out what was causing the crash.

You can see the full code in this commit of branch 5-upgrade-mvvmcross.

Let’s start up the app to see how it looks:

After Upgrading MvvmCross

and here’s the post activity:

After Upgrading MvvmCross

The text is now white again - it looks great!

Now we have a toolbar in our layout, we’re finally ready to implement our quick return toolbar…

Quick Return Toolbar

There’s a good article explaing how to implement the quick return pattern here.

You can see my implementation in this commit of master.

The key is to use a CoordinatorLayout. The CoordinatorLayout listens for scroll events on one view and then does some specified behavior on another view.

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            local:layout_scrollFlags="scroll|enterAlways"
            local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    </android.support.design.widget.AppBarLayout>

    <MvxRecyclerView
        android:id="@+id/listPosts"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        local:layout_behavior="@string/appbar_scrolling_view_behavior"
        local:MvxItemTemplate="@layout/item_post"
        local:MvxBind="ItemsSource Posts; ItemClick ShowPostCommand" />
</android.support.design.widget.CoordinatorLayout>

I’ve inlined the toolbar for this example so that it’s easier to see the relationship between the controls.

The important things to note are:

  1. The Toolbar and the RecyclerView are wrapped in a CoordinatorLayout

  2. On line 26, the layout_behavior attribute identifies the view that is responsible for scrolling

  3. On line 16, the layout_scrollFlags attribute identifies how the view should respond to scrolling

Let’s have a look at the finished scrolling effect. Tap / click on this GIF to see it in action:

Quick Return Toolbar

Wrap Up

It’s been a bit of a journey to implement the quick return toolbar in our application. MvvmCross is a great framework that can help boost code-reuse for Xamarin cross platform projects.

Additionally, my WPF background means that I love the MVVM pattern and data binding - features that are at the core of MvvmCross.

It it worth noting that major new features come along once in a while - like fragments, AppCompat etc.

Xamarin has an excellent track record in supporting these new features very quickly.

However, if you’re using a framework on top of Xamarin, you may not be using these new features as quickly as you, or your designer, would like.