Xamarin Android Compound Control - Styling

Last time around I showed how to create a Xamarin Android compound TextInputLayout control with support for capturing user input with an associate Header and Error labels. This post looks at how to style the same control in Android.

Style attributes

As mentioned previously, I want all my compound controls to support a common set of attributes to create a consistent look-and-feel. Every control will have a Header (i.e. description), Text (i.e. value) and Error properties. To style these attributes, we create three associated attributes in our Resources/values/attrs.xml file to assign the styles to:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="ItcTextAppearanceLabel" format="reference"/>
    <attr name="ItcTextAppearanceText" format="reference"/>
    <attr name="ItcTextAppearanceError" format="reference"/>

In addition to these attributes we also associate these new style attributes with our existing ITTextInputLayout definition in the attrs.xml:

<declare-styleable name="ITTextInputLayout" >
    <attr name="android:inputType"/>
    <attr name="android:maxLines"/>
    <attr name="android:text"/>
    <attr name="android:imeOptions"/>
    <attr name="ItcLabel"/>
    <attr name="ItcError"/>
    <attr name="ItcTextAppearanceLabel"/>
    <attr name="ItcTextAppearanceError"/>       		
</declare-styleable>  

Notice that we don’t include the ItcTextAppearanceText reference style in the definition. The reason being that we will re-use the already defined style attribute on the android.support.design.widget.TextInputLayout that our ITTextInputLayout control inherits from.

To define the default, global look-and-feel for all our controls, we also create a styles container in the attrs.xml:

<declare-styleable name="ITControls" >		
    <attr name="ItcTextAppearanceLabel"/>
    <attr name="ItcTextAppearanceError"/>               
    <attr name="ItcTextAppearanceText"/>
    <attr name="ItcTextInputLayoutStyle" format="reference"/>   
</declare-styleable>  

Widget and TextAppearance styles

With the attributes defined, we can now define a style for our compound control in the Resources/values/styles.xml file. As our control extends the android.support.design.widget.TextInputLayout control, it is important to first consider what style attributes is already being used so that we can associate our own styles with the existing styles. From the existing Android styles definition we see that Android widget has the following styles definition:

<style name="Widget.Design.TextInputLayout" parent="android:Widget">
  <item name="hintTextAppearance">@style/TextAppearance.Design.Hint</item>
  <item name="errorTextAppearance">@style/TextAppearance.Design.Error</item>
  <item name="counterTextAppearance">@style/TextAppearance.Design.Counter</item>
  <item name="counterOverflowTextAppearance">@style/TextAppearance.Design.Counter.Overflow</item>
  <item name="passwordToggleDrawable">@drawable/design_password_eye</item>
  <item name="passwordToggleTint">@color/design_tint_password_toggle</item>
  <item name="passwordToggleContentDescription">@string/password_toggle_content_description</item>
</style>

The hintTextAppearance and errorTextAppearance is being used by the Android widget to style the label and error text. With this in mind, we can now create a style definition for our own control:

<style name="Widget.InTouch.TextInputLayout" parent="Widget.Design.TextInputLayout">
  <item name="android:textColorHint">@color/accentColor</item>
  <item name="hintTextAppearance">?attr/ItcTextAppearanceLabel</item>
  <item name="errorTextAppearance">?attr/ItcTextAppearanceError</item>      
</style>

We override the default style styles and associate them with our new common-look-and-feel style attributes that we have defined. With our control style defined, we also create the default text appearance styles to use for our common-look-and-feel:

<style name="TextAppearance.InTouch" parent="TextAppearance.AppCompat">
</style>

<style name="TextAppearance.InTouch.Label">
  <item name="android:textSize">14sp</item>
</style>

<style name="TextAppearance.InTouch.Label.Error">
  <item name="android:textSize">12sp</item>
  <item name="android:textColor">@color/errorColor</item>
</style>

Themes

With the styles defined, we now set out to create a default Theme where we assign the default styles to the style attributes we created to create our common look-and-feel. Themes are created in a Resources/values/themes.xml file:

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <style name="Theme.InTouch" parent="Theme.InTouch.Base">
  </style>

  <style name="Theme.InTouch.Base" parent="Theme.Design.Light.NoActionBar">

    <item name="colorPrimary">@color/primaryColor</item>
    <item name="colorPrimaryDark">@color/primaryColorDark</item>
    <item name="colorAccent">@color/accentColor</item>

	<!-- Composites -->
    <item name="ItcTextAppearanceLabel">@style/TextAppearance.InTouch.Label</item>
    <item name="ItcTextAppearanceError">@style/TextAppearance.InTouch.Label.Error</item>
    <item name="ItcTextInputLayoutStyle">@style/Widget.InTouch.TextInputLayout</item>   
  </style>

Notice that our theme associates the default text appearance with a specific style. With the theme definition in place, we can now use it our applications in Xamarin by typically assigning the Theme property as an attribute on our startup Activity or on the Application instance as illustrated below:

[Application(Name = "phil.AndroidApp", Theme = "@style/Theme.InTouch")]
public class AndroidApp : Application, Application.IActivityLifecycleCallbacks
{

Control changes

With the style attributes and themes defined, we still need to enhance our control to make use of the styles defined. To cater for the styles and themes we need to change our existing control to get the style definitions and use them for changing the look-and-feel of its internal widgets:

The three different constructors cater for different scenarios of creating our compound control. The first constructor on Line 3 is typically used when I create a control programmatically. The second constructor on Line 7 is called when I define my control in a layout without specifying a style.

<intouch.controls.ITTextInputLayout
    android:id="@+id/layout_username"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:imeOptions="actionNext" ...

The third constructor is called when I define my control in a layout with specifying a style:

<intouch.controls.ITTextInputLayout
    style="@style/MyCustom.Style"
    android:id="@+id/layout_username"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:imeOptions="actionNext" ...

Notice how the constructors call into each other and the use of the Resource.Styleable.ITControls_ItcTextInputLayoutStyle style attribute on Line 7 that will use the style setup in our theme as the default if the user does not specify their own style for our control in a layout. Our theme is setup to use @style/Widget.InTouch.TextInputLayout as style which makes use of the default look-and-feel style attributes to style the control.

As we are re-using the existing styles defined on the Android TextInputLayout control, we simply have to call into the base class constructor to get these styles applied to the Error and Hint widgets. Feel free to browse the TextInputLayout.java source code if you want to see how this is done.

Summary

Styles and Themes in Android along with style inheritance is a really powerful tool for creating a common look-and-feel across your application. I hope this post highlighted some ways in which you can make use of this powerful functionality to create a common look-and-feel for your own compound controls.

Xamarin Android Compound TextInputLayout Control

I’ve been going through some Android layouts try and remove some duplication by creating re-usable custom component controls. I’m pretty happy with how things are turning out and thought I’d share one or two of the controls. I will show how these controls can be used in vanilla Xamarin Android as well as in my favourite MVVM framework, MvvmCross.

Shared attributes

I want all my compound controls to support a common set of attributes to create a consistent look-and-feel. Every control will have a Header (i.e. description), Text (i.e. value) and Error properties. For this I define a IITComposite interface.

All my custom compound controls will implement this interface.

Custom TextInputLayout Control

The first compound control will be used to capture text input from the user. Most of the functionality is already provided out-of-the-box via the TextInputLayout and TextInputEditText views of the Android.Support.Design library.

Here’s a screen shot of of these controls in action in one of my apps:

Here’s the corresponding layout for the password field:

People familiar with MvvmCross will understand the binding syntax being used by the app:MvxLang and app:MvxBind attributes. The binding is what makes a MVVM framework so powerful and I’m not going to delve into the details here. From the binding syntax we can see that the Hint, Text and Error properties of the views map nicely to the features required by my IITComposite interface. It therefore makes sense for my compound view to re-use by inheriting and extending the existing TextInputLayout control.

Control Layout

We start by defining the layout for the compound control that will be inflated in code within a Resources\layout\control_textinput.axml file:

As the compound control inherits from TextInputLayout, the merge tag is being used instead of the android.support.design.widget.TextInputLayout tag to prevent an extra instance of the control being inflated when my custom component control is included in a layout.

Control Layout Attributes

To define the set of attributes that can be set for a control in layout, you have to create a Resources\values\attrs.xml file and include a definition for your control and its supported attributes within it.

Notice that the ITTextInputLayout adds support for its own ItcHeader and ItcError attributes, but for the rest makes use of the default Android attributes already associated with TextInput controls.

Given the above attributes definition, the layout for the same password field using the ITTextInputLayout control can be simplified to:

Notice that the control now supports the IITComposite interface through the Header,Text and Error properties. Again, the code snippet illustrates these properties being set using the binding functionality of MvvmCross. I can however also set them manually as shown by using the app:ItcHeader attribute to set the Header property in the following snippet:

Control Properties

With these attributes defined, we can now populate the properties for our control from the layout definition (lines 8-27):

We first inflate our control and then assign the attribute values from the layout to the public properties of the control. These properties are mapped to the internally inflated controls to drive the behavior of the compound control.

Control Events

To allow external consumers to be notified of the text being entered, we add a TextChanged event to the compound control.

We hook/unhook the Control.AfterTextChanged event via the OnAttachedToWindow and OnDetachFromWindow methods and raise our own TextChanged event whenever we get notified by the internal TextEditInputView.

In a follow up post I will show how easy it is to create a custom MvvmCross binding for the ITTextInputLayout.TextChanged event to automatically bind the changes to a data context.

Summary

That’s about it for now. You can find a gist for the complete code of the ITTextInputLayout control here. I also highly recommend reading through the transcript of this talk by Daniel Lew on how to create efficient Android layouts.

Building a non-trivial cross platform app using Xamarin

Over the past year or two we’ve been using Xamarin to build a moderately complex mobile application. On Key Work Manager is a mobile work order management solution that enables your field service staff to manage their work assignments and forms part of the On Key Enterprise Asset Management system.

To illustrate why I say this is as a moderately complex app, here are some of the features:

  • Location tracking
  • Maps integration
  • Electronic PDF form filling and generation
  • Electronic signatures to support signing off job cards
  • Barcode scanning of assets
  • Document attachments including photos, in-app voice recordings etc.
  • Local notifications
  • Background services to synchronise data whilst the app is not running
  • Full offline support - i.e. app functionality works in offline environments and only requires peridic connectivity to synchronise changes to server

Based on local market demands, we targeted Android first and published the Android version of the application mid 2016. Last week we published the iOS version of the application.

I’ve had one or two enquiries from people on what tools/libaries/frameworks we used to build the app. This post will give a rundown of what we use.

Frameworks

One of the principles we followed from the word go, was to try and maximize the re-use of shared logic across the different platforms. The team had experience using the MVVM pattern so we decided on using a framework that would supprt the MVVM pattern. Xamarin Forms was still in its infancy at that stage so we decided to look for a framework that would allow us to build directly on top of the native platform thus giving us full access to the native platform performance, native iOS and Android controls, native navigation mechanisms etc.

We ended up using a blend of the excellent MvvmCross and our own small homegrown framework that covered aspects like navigation and bootstrapping a bit differently as to how MvvmCross prescribes. This is a big shout out to the community members behind MvvmCross like Tomasz and Martijn00. The fact that we were able to replace aspects of MvvmCross is also a compliment to the overall design of the framework. MvvmCross v5 is shaping up to be an awesome release as well.

Using the MVVM pattern we are able to share up to 70-75% of the code base between the different platforms in a PCL library.

Testing

We have an extensive set of NUnit unit tests covering the shared logic contained in our PCL library that we execute on our TeamCity CI server. We are also in the early phases of using Xamarin.UITest to do automated UI testing.

Plugins/3rd Party Components

We use the following plugins/components to support the app features:

NuGet Packages/Libraries

Besides the frameworks/plugins/controls, we use the following NuGet packages:

Testing/Analytics/Crash Reporting

For ALPHA, BETA testing, crash reporting and application insights we use HockeyApp

I think that’s about it! Since we started using Xamarin, the whole ecosystem around Xamarin including the plugins, components have evolved quite nicely. This allows us to focus on building the features of our app instead of having to re-invent the wheel. Overall we are quite happy with how our code base has turned out and we are looking forward to building more apps using Xamarin.

Messaging Plugin for Xamarin 4 released

I’ve just published the final build of the next major version of the Messaging Plugin to NuGet. I’ve added no new features since the last beta build.

Here is the complete list of changes for v4 of the plugin:

  • Add support for sending SMS to multiple recipients
  • Android+UWP: Add support for sending SMS without user interaction via the ISmsTask.CanSendSmsInBackground and ISmsTask.SendSmsInBackground
  • Android: Add support for using FileProvider to add attachments using content Uri’s on Android Nougat and later
  • Android: Add new Settings class to configure Android specific behavior when sending emails/making phone calls (see next bullets). Access from Android project only using CrossMessaging.Current.Settings() extension method.
    • Add new EmailSettings.UseStrictMode flag (default value false) to filter list of apps to only email apps and not other text messaging or social apps. Unfortunately adding attachments when using StrictMode does not seem to work, and is therefore currently not supported.
    • Add new PhoneSettings.AutoDial flag (default value false) to automatically phone the number instead of only showing the phone dialer with the number populated. Please note using this settings requires the android.permission.CALL_PHONE added to the manifest file.
  • Breaking Change: Remove iOS Classic support
  • Breaking Change: Remove Windows Phone 8.0 and 8.1 support
  • Breaking Change: Reworked EmailMessageBuilder.WithAttachment platform API to provide consistent API

Full details of how to use the plugin can be found here. You can also find samples illustrating the use of the different features in the GitHub repo.

Messaging Plugin for Xamarin 4 Beta

I’ve just published another beta build of the next major version of the Messaging Plugin to NuGet.

New feature added in this build:

  • Android+UWP: Add support for sending SMS without user interaction via the ISmsTask.CanSendSmsInBackground and ISmsTask.SendSmsInBackground. Thanks to soroshsabz for the initial contribution.

I’m hoping that this is the final build before publishing v4 of the plugin. Take it for a spin and let me know if you run into any issues