Xamarin Mobile Development for Android Cookbook

5 (1 reviews total)
By Matthew Leibowitz
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Working with Xamarin.Android

About this book

Xamarin is used by developers to write native iOS, Android, and Windows apps with native user interfaces and share code across multiple platforms not just on mobile devices, but on Windows, Mac OS X, and Linux.

Developing apps with Xamarin.Android allows you to use and re-use your code and your skills on different platforms, making you more productive in any development. Although it’s not a write-once-run-anywhere framework, Xamarin provides native platform integration and optimizations. There is no middleware; Xamarin.Android talks directly to the system, taking your C# and F# code directly to the low levels.

This book will provide you with the necessary knowledge and skills to be part of the mobile development era using C#. Covering a wide range of recipes such as creating a simple application and using device features effectively, it will be your companion to the complete application development cycle.

Starting with installing the necessary tools, you will be guided on everything you need to develop an application ready to be deployed. You will learn the best practices for interacting with the device hardware, such as GPS, NFC, and Bluetooth. Furthermore, you will be able to manage multimedia resources such as photos and videos captured with the device camera, and so much more! By the end of this book, you will be able to create Android apps as a result of learning and implementing pro-level practices, techniques, and solutions. This book will ascertain a seamless and successful app building experience.

Publication date:
November 2015
Publisher
Packt
Pages
456
ISBN
9781784398576

 

Chapter 1. Working with Xamarin.Android

In this chapter, we will cover the following recipes:

  • Creating Xamarin.Android projects

  • Creating user interface layouts

  • Creating an option menu

  • Supporting previous Android versions

  • Adding an action bar

  • Navigating with the action bar

  • Adding action bar action items

  • Creating contextual action mode menu

  • Sharing code with other platforms

 

Introduction


Xamarin.Android allows us to create native Android applications using the same UI controls we would use in Java, with the flexibility of C#, the power of the .NET Base Class Library, and two first-class IDEs.

Android development with Xamarin can be done on either Mac OS X or Windows, using either Visual Studio or Xamarin Studio. This variety provides us with our choice of how we want to work to create awesome apps.

This book will enable us, as developers, to create amazing, professional apps for the Android ecosystem. This knowledge can be used on so many platforms, from TVs and smartphones to watches, wearables, and many other Android-powered devices.

This chapter covers some of the most common tasks and steps to getting our app ready for development. We will learn how to create a new app, add support for the old versions of Android, and get started with the user interface used in all Android apps. We will also look at just how powerful the Xamarin.Android platform is by looking how we can share code with many other platforms, including Windows Phone, iOS, Windows, and Mac.

 

Creating Xamarin.Android projects


Before any apps can be created, the development environment has to be set up and the software downloaded and installed.

Getting ready

Before we start creating any Android apps, we need to get our tools in place using the installer from Xamarin.

  1. Go to http://xamarin.com/download:

  2. Enter your details for registration.

  3. Click on the Download Xamarin for Windows or Download Xamarin for OS X links, depending on the operating system you are using.

  4. Once the download has completed, launch the installer, following the on-screen instructions. Setup will continue to download and install all the required components:

  5. Once the installer has finished, you should have a working installation of Xamarin Studio, the IDE designed for cross-platform development.

How to do it...

Creating Xamarin.Android projects is very simple!

  1. Open Xamarin Studio.

  2. Select File, then New, and then Solution…:

  3. Select C#, then Android, and then Android Application:

  4. Enter a name for your app, for example XamarinCookbook.

  5. Click on OK.

  6. We now have a fully functional Xamarin.Android app, which can be deployed to a device or an emulator.

  7. In the target device dropdown, select either an emulator or your device (if you have attached an Android device).

  8. Finally, click on Run and the app will install and launch.

How it works...

Xamarin.Android allows us to write native Android apps using .NET and C# or F#. Xamarin.Android does not abstract or emulate any Android features. Rather, it is an alternate programming language available for the development of Android apps.

Tip

Whatever can be done in Java, and much more, can be done in C#.

Some of the benefits of using Xamarin.Android are found in the small things. For example, if we are using Android Studio or Eclipse, we will have to make changes in AndroidManifest.xml. If we are using Xamarin.Android, we can do much of this work by using the familiar attributes.

Tip

Various attributes can be used to provide the same functionality that modifying the AndroidManifest.xml file would bring.

To add the <activity> element into the manifest with Xamarin.Android, we add the [Activity] attribute on an activity as follows:

[Activity(
  Label = "My App", 
  MainLauncher = true, 
  Icon = "@drawable/icon")]
public class MainActivity : Activity
{
}

This will create a section in ApplicationManifest.xml at compile time, as highlighted in the following code:

<activity android:label="My App"
  android:icon="@drawable/icon"
  android:name="mynamespace.MainActivity">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

If we want to add permissions to our app, all we need to do is add this:

[assembly: UsesPermission(Manifest.Permission.Camera)]

There are many other attributes that help us build the manifest file, such as the [Service] and [IntentFilter] attributes.

 

Creating user interface layouts


All apps require some form of user interface for the user to input data or view the output of information.

How to do it...

Creating an interface for our apps is very easy. There are two ways to create user interfaces, with code or with XML:

  • If we are using code to create a button on the screen, we would do something similar to this:

    protected override void OnCreate(Bundle bundle)
    {
      base.OnCreate(bundle);
    
      LinearLayout layout = new LinearLayout(this);
      layout.Orientation = Orientation.Vertical;
    
      Button button = new Button(this);
      button.Text = "Hello World!";
      layout.AddView(
        button, 
        ViewGroup.LayoutParams.MatchParent,
        ViewGroup.LayoutParams.WrapContent);
    
      SetContentView(layout);
    }

Both XML and code can be used to create equivalent UIs, but using XML, we have additional capabilities:

  • The equivalent interface in XML would be created and stored in the layout sub-folder of the Resources folder and reads as follows:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
     xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/layout"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical">
      <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
    </LinearLayout>

    Once we have created the interface in XML, we have to indicate to the activity which layout file is to be used. This is done by invoking the SetContentView() method in the OnCreate() method of the activity. For example, say we named our layout file Main.axml:

    protected override void OnCreate(Bundle bundle)
    {
      base.OnCreate(bundle);
    
      // note the name "Main"
      SetContentView(Resource.Layout.Main);
    }

Regardless of whether the layout was created in code or through XML files, we are able to access the various controls similarly:

  • In order to access the control at runtime, we make use of the FindViewById method on the activity or a view (use the View property of a fragment):

    Button btn = FindViewById<Button>(Resource.Id.buttonId);

How it works...

Separating the UI from the code allows us to easily make changes for updates as well as to support different screen configurations. The benefit of this is that it allows us to modify the UI without updating the code. And part of this is the fact that the Android system can switch the entire layout at runtime. Different layouts for different screen configurations can be selected simply by changing the suffix of the layout folder name.

Tip

Fragments can be used in addition to layouts to create advanced interfaces consisting of self-contained, reusable regions.

For example, if we want our Main layout to have the LinearLayout method to be vertical in portrait orientation and horizontal in landscape orientation, all we have to do is create two layout files with the same name in different folders as follows:

<project-root>/Resources/layout/<layout-file-name>.axml
<project-root>/Resources/layout-land/<layout-file-name>.axml

There are many uses for the suffixes, and there are many different suffixes. Each of the resource subfolders can have suffixes, including values, layout, menu, and drawable. Each of the folders can have combinations of the suffixes for language or culture, screen orientation, screen density, screen size, and platform version. More information can be found online at https://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources.

The Android layout structure usually follows the structure of the type, with the element name matching the type name and property names matching the attribute names. For example, the Button type has a Text property; thus, the XML will have a <Button android:text="..." /> element.

Although we can nest one or more layouts within another layout, we should strive to keep our layout hierarchy as shallow as possible. The layout will be drawn faster if it has fewer nested layouts.

Tip

A wide view hierarchy is better than a deep view hierarchy.

One of the most important attributes in layouts is the id attribute. This attribute is used to uniquely identify a view within a tree. An ID need not be unique throughout the entire tree, but it should be unique within the part of the tree that is being searched.

Tip

The ID need not be unique, but it's best to be completely unique when possible so that the specific view can be found in the hierarchy.

There's more...

Layout files are an easy way to create the UI separate from the code, and in the same way, resource files can be used to separate the localizable text from the layout. This is achieved by placing the strings into a resource file and then, referencing each the string from the layout. Say we have a button that has some text:

<Button android:text="Hello World!" />

This value can be extracted and placed into a file under the values folder of the project resources (<project-root>/Resources/values/<file-name>.xml):

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="buttonText">Hello World!</string>
</resources>

The layout file can then be updated to reference the value:

<Button android:text="@string/buttonText" />

Using this pattern, we are able to not only extract strings but any value for any attribute, including layout information. An example would be to extract an element's padding and use a larger padding for larger screens. These types of resources are placed in the values folder with a suffix, such as -large for large screens.

See also

 

Creating an options menu


Android provides the user with the ability to display a special type of menu that contains a set of items that pertains to the entire app, instead of the current activity.

How to do it...

Adding an options menu to our app is very simple, and only two things are required: a menu structure and code to connect the menu with the activity. In order to use a menu layout file, a resource file needs to be added:

  1. First, we create a new XML file with the name of the menu, for example Options.xml, in the menu folder under the Resources folder.

  2. Then, we create the menu structure in this file, for example, create three menu items: refresh, settings, and about.

    <?xml version="1.0" encoding="utf-8" ?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
      <item
        android:id="@+id/action_refresh"
        android:icon="@drawable/ic_action_refresh"
        android:title="@string/action_refresh" />
      <item
        android:id="@+id/action_settings"
        android:title="@string/action_settings" />
      <item
        android:id="@+id/action_about"
        android:title="@string/action_about"/>
    </menu>
  3. Once we have the structure, we override the OnCreateOptionsMenu() method and inflate the resource:

    public override bool OnCreateOptionsMenu(IMenu menu)
    {
      MenuInflater.Inflate(Resource.Menu.Options, menu);
      return true;
    }
  4. If we want to respond to items being selected in that menu, all we need to do is override the OnOptionsItemSelected() method:

    public override bool OnOptionsItemSelected(IMenuItem item) {
      if (item.ItemId == Resource.Id.action_refresh) {
        // do something here...
        return true; // we handled the event
      }
      return base.OnOptionsItemSelected(item);
    }

How it works...

Menus, especially the options menu, are both simple and important to Android apps. The Options menu contains items that are relevant to the current activity. They are important, but they are often not commonly used and so don't have a dedicated space in the layout.

An Android screen with an options menu at the bottom

As with traditional layout files, using resource files for menus allows greater flexibility for the many screen configurations as well as for simplifying customizations to menus.

Each menu item contains a unique ID, which allows the system to recognize the item when the user selects it, and a title, which is used to present the item to the user. There are also additional properties, the most commonly used of these being the icon. When using action bars, this icon is used to display an image alongside, or in place of, the title.

Tip

Although not required, it is recommended that most menu items include an icon.

The MenuInflater instance creates the menu structure from the resource file and inflates it into the IMenu instance. All the menu items in the resource will be added as children to the menu.

Note

The OnCreateOptionsMenu() method should return true if the menu is to be displayed. Returning false will result in the menu not being displayed.

When we handle the menu item selections, the menu item that was selected is passed into the OnOptionsItemSelected() method. If the event was handled, true should be returned; otherwise, the system will keep on processing the event.

We can use any of the properties on the menu item, but one of the more commonly used ones is ItemId, which contains the ID that was used in the resource file. This ID can be used to determine which item was selected.

 

Supporting previous Android versions


As the Android operating system evolves, many new features are added and older devices are often left behind.

How to do it...

In order to add the new features of the later versions of Android to the older versions of Android, all we need to do is add a small package:

  1. An Android app has three platform versions to be set. The first is the API features that are available to code against. We set this to always be the latest in the Target Framework dropdown of the project options.

  2. The next version to set (via Minimum Android version) is the lowest version of the OS that the app can be installed on. When using the support libraries, we can usually target versions down to version 2.3.

  3. Lastly, the Target Android version dropdown specifies how the app should behave when installed on a later version of the OS. Typically, this should always be the latest version so the app will always function as the user expects.

If we want to add support for the new UI paradigm that uses fragments and action bars, we need to install two of the Android support packages:

  • Create or open a project in Xamarin Studio.

    1. Right-click on the project folder in the Solution Explorer list.

    2. Select Add and then Add Packages….

    3. In the Add Packages dialog that is displayed, search for Xamarin.Android.Support.

    4. Select both Xamarin Support Library v4 and Xamarin Support Library v7 AppCompat.

    5. Click on Add Package.

There are several support library packages, each adding other types of forward compatibility, but these two are the most commonly used.

  1. Once the packages are installed, our activities can now inherit from the AppCompatActivity type instead of the usual Activity type:

    public class MyActivity : AppCompatActivity
    {
    }
  2. Finally, we specify that the activity theme be one of the AppCompat derivatives using the Theme property in the [Activity] attribute:

    [Activity(..., Theme = "@style/Theme.AppCompat", ...)]

How it works...

As Android is developed, new features are being added and designs change. We want to always provide the latest features to our users, but some users either haven't or can't upgrade to the latest version of Android. By including the Android Support Libraries in our app, we can make use of the new features, but still support the old versions.

Note

Types from the Android Support Library are available to almost all versions of Android currently in use.

Xamarin.Android provides three version numbers to specify what and how types can be used. The target framework version specifies what types are available for consumption as well as what toolset to use during compilation. This should be the latest as we always want to use the latest tools.

However, this will make some types and members available to apps even if they aren't actually available on the Android version that the user is using. For example, it will make the ActionBar type available to apps running on Android version 2.3. If the user were to run the app, it would probably crash.

In these instances, we can set the minimum Android version to be a version that supports these types and members. But, this will then reduce the number of devices that we can install our app on. This is why we use the support libraries; they allow the types to be used on most versions of Android.

Tip

Setting the minimum Android version for an app will prevent the app from being installed on devices with earlier versions of the OS.

The Android support libraries provide us with a type that we know we can use everywhere, and then that base type manages the features to make sure they function as expected. For example, we can use the ActionBar type on most versions of Android because the support library made it available through the AppCompatActivity type.

Because the AppCompatActivity type is an adaptive extension for the traditional Activity type, we have to use a different theme. This theme adjusts so that the new look and feel of the UI gets carried all the way back to the old Android versions.

Note

When using the AppCompatActivity type, the activity theme must be one of the AppCompat theme variations.

There are a few differences when using the support library. With native support for the action bar, the AppCompatActivity type has a property named ActionBar; however, in the support library, the property is named SupportActionBar. This is just a property name change, but the functionality is the same.

Sometimes, features have to be added to the existing types that are not in the support libraries. In these cases, static methods are provided. The native support for custom views in menu items includes a method named SetActionView:

menuItem.SetActionView(someView);

This method does not exist on the IMenuItem type for the older versions of Android, so we make use of the static method on the MenuItemCompat type:

MenuItemCompat.SetActionView(menuItem, someView);

There's more...

Besides using the Android Support Libraries to handle different versions, there is another way to handle different versions at runtime. Android provides us with the version number of the current operating system through the Build.VERSION type.

This type has a property, SdkInt, which we can use to detect the current version. It represents the current API level of the version. Each version of Android has received a series of updates and new features. For example, Android 4 has received numerous updates since its initial release, new features being added each time.

Sometimes the support library cannot cover all the cases, and we will have to write specific code for particular versions:

int apiLevel = (int)Build.VERSION.SdkInt;
if (Build.VERSION.SdkInt >= BuildVersionCodes.IceCreamSandwich) {
  // Android version 4.0 and above
} else {
  // Android versions below version 4.0
}

Although this can be done, it introduces spaghetti code and should be avoided. In addition to different code, the app may behave differently on different versions, even if the support library could have handled it. We will now have to manage these differences ourselves each time a new version of Android is released.

 

Adding an action bar


Almost all apps require some form of commanding, usually being frequently used. As a result, these commands should be presented in an easily consumed region of the screen, regardless of differences in screen configuration.

How to do it...

Adding an action bar is very simple and does not need many changes to our app, even if they are to run on the old versions of Android:

  1. By default, on Android 4.0, apps will have an action bar. To access this, we can use the ActionBar property on the Activity type:

    ActionBar.Title = "Xamarin Cookbook"; 

To provide an action bar to previous versions of Android, we use the Android Support Libraries:

  1. First, we need to install the Xamarin Support Library v7 AppCompat Component or NuGet.

  2. Then, we need to ensure our activities inherit from the AppCompatActivity type instead of the usual Activity type:

    public class MyActivity : AppCompatActivity
    {
    }
  3. Next, we add the Theme property to the [Activity] attribute:

    [Activity(..., Theme = "@style/Theme.AppCompat")]
  4. Finally, if we need to access the ActionBar instance, it is available via the SupportActionBar property on the activity:

    SupportActionBar.Title = "Xamarin Cookbook";

How it works...

Certain commands are used very frequently in an app. These commands are often the main set of actions available to the current app screen. Because these commands are so important, they have a dedicated area in the app, often at the top of the screen. In a to-do list app, this might be the action to add a new task. In a shopping app, this might be the option to search for a product.

An Android screen with an action bar at the top

While adding an action bar on older Android versions, it is important to inherit it from the AppCompatActivity type. This type includes all the logic required for including an action bar in the app. It also provides many different methods and properties for accessing and configuring the action bar. In newer versions of Android, all the features are included in the Activity type.

Although the functionality is the same, we do have to access the various pieces using the support members when using the support libraries. An example would be to use the SupportActionBar property instead of the ActionBar property. If we use the ActionBar property, the app will crash on devices that don't natively support the ActionBar property.

In order to render the action bar, the activity needs to use a theme that contains a style for the action bar or one that inherits from such a theme. For the older versions of Android, we can use the AppCompat themes, such as Theme.AppCompat.

There's more...

With the release of Android version 5.0, Google introduced a new style of action bar. The new Toolbar type performs the same function as the action bar but can be placed anywhere on the screen. The action bar is always placed at the top of the screen, but toolbar is not restricted to that location and can even be placed inside other layouts.

To make use of the Toolbar type, we can either use the native type, or we can use the type found in the support libraries. Like any Android View, we can add the ToolBar type to the layout:

<android.support.v7.widget.Toolbar
  android:id="@+id/my_toolbar"
  android:layout_width="match_parent"
  android:layout_height="?attr/actionBarSize"
  android:background="?attr/colorPrimary"
  android:elevation="4dp"
  android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
  app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

The difference is in how the activity is set up. First, as we are not going to be using the default ActionBar property, we can use the Theme.AppCompat.NoActionBar theme. Then, we have to let the activity know which view is the Toolbar type:

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

See also

  • The Supporting previous Android versions recipe

  • The Adding action bar action items recipe

 

Navigating with the action bar


The action bar is used to allow the user to navigate to a parent activity, as well as show the user where they are in the app.

How to do it...

Navigation with the action bar is an upward navigation, rather than a backward navigation. This navigation is very simple to add and involves only two steps. If we support versions of Android versions below 4.1, we will make use of the support library.

  1. First, we need to ensure that our source activity is accessible using a known name by adding a [Register] attribute:

    [Register("com.xamarincookbook.MainActivity")]
    public class MainActivity : AppCompatActivity
    {
    }
  2. Next, we let the system know which activity we want to navigate up to using a [MetaData] attribute:

    [MetaData(
      "android.support.PARENT_ACTIVITY", 
      Value = "com.xamarincookbook.MainActivity")]
    public class RecipeDetailsActivity : AppCompatActivity {
    }
  3. Then in the child activity, we let the action bar know that we want to allow upward navigation:

    SupportActionBar.SetDisplayHomeAsUpEnabled(true);

If the Android version is 4.1 and above, we use the native types and members:

  1. First, we set the ParentActivity property on the [Activity] attribute:

    [Activity (ParentActivity = typeof(MainActivity))]
    public class RecipeDetailsActivity : Activity
    {
    }
  2. Then, we let the child activity's action bar know that we want to allow upward navigation:

    ActionBar.SetDisplayHomeAsUpEnabled(true);

How it works...

The action bar can facilitate direct navigation in two ways: navigating up to the parent activity and navigating down to a child activity. Navigating down is often done by adding action items to the action bar.

Action bar automatically navigates up to the parent activity when the user taps the icon, which is different from the traditional back navigation. The up navigation within an app is based on the hierarchical relationships between activities, that is, navigation to the parent activity. The back navigation is navigation back through the history of activities, in reverse chronological order.

Tip

If an activity is the topmost one in an app and it does not have a parent activity, it should not present an up button.

Sometimes the back navigation is the same as the up navigation. This happens when the previously viewed screen is also the hierarchical parent of the current screen. However the up navigation will keep the user in the app, but back navigation may return the user to the home screen or another app.

When adding the [MetaData] attribute to the activity, we need to reference the final compiled name of the parent activity. Xamarin.Android mangles the final name of the types to avoid possible conflicts, so we have to let the compiler know exactly what name to use. We do this using a [Register] attribute on the parent activity, and we then use the same value for the value component of the metadata.

The action bar lets the user know where they are in the app by using the action bar's title, which is usually the current activity's label. This can be customized by assigning a new string value to the Title property on the ActionBar instance.

There's more...

Sometimes the up navigation will take the user to different parent activities, depending on how the user arrived at the current activity. In these cases, we override several members in our activity. If our app is not going to have the activity instantiated on any other apps, we only need to override the SupportParentActivityIntent or ParentActivityIntent properties:

public override Intent SupportParentActivityIntent {
  get {return new Intent(this, typeof(MainActivity));}
}

If our activity is going to be used by other apps, we also need to override the OnCreateNavigateUpTaskStack() or OnCreateSupportNavigateUpTaskStack() method.

See also

  • The Adding an action bar recipe

 

Adding action bar action items


The fundamental purpose of an action bar, besides navigation, is to present the user with a set of actions that can be performed.

How to do it...

By simply using the action bar, all the action items are added to the overflow:

  1. The XML for ActionBar items is exactly the same as the options menu:

    <menu ... >
      <item
        android:id="@+id/action_refresh"
        android:icon="@drawable/ic_action_refresh"
        android:title="@string/action_refresh"/>
    </menu>

However, we can customize what items are displayed, and how they are displayed:

  1. To add action items with images to the actual ActionBar property, as well as more complex items, all that is needed is an attribute in the XML, showAsAction:

    <menu ... xmlns:app="http://schemas.android.com/apk/res-auto">
      <item ... app:showAsAction="ifRoom"/>
    </menu>
  2. If we wish to add custom views, such as a search box, to the action bar, we make use of the actionViewClass attribute:

    <menu ... xmlns:app="http://schemas.android.com/apk/res-auto">
      <item ...
      app:actionViewClass="android.support.v7.widget.SearchView"/>
    </menu>
  3. If the view is in a layout resource file, we use the actionLayout attribute:

    <menu ... xmlns:app="http://schemas.android.com/apk/res-auto">
      <item ... app:actionLayout="@layout/action_rating"/>
    </menu>
  4. Sometimes, we may wish to only display the icon initially and then, when the user taps the icon, expand the item to display the action view:

    <menu ... xmlns:app="http://schemas.android.com/apk/res-auto">
      <item ... app:showAsAction="ifRoom|collapseActionView"/>
    </menu>

How it works...

Action item buttons are just traditional options menu items but are optionally always visible on the action bar.

The underlying logic to handle item selections is the same as that for the traditional options menu. No change is required to existing code inside the OnOptionsItemSelected() method.

The value of the showAsAction attribute can be ifRoom, never, or always. This value can optionally be combined, using a pipe, with withText and/or collapseActionView.

 

Creating contextual action mode menu


Some controls or regions in the user interface allow for additional actions to be performed. However, due to limited screen space, these actions need to be hidden until the user requests them.

How to do it...

  1. The first thing that needs to be done is to let the activity or fragment know that we want to display a popup menu when the user long-taps on a view:

    this.RegisterForContextMenu(someView);
  2. Then, following the pattern of the options menu, we create or inflate the menu items in the OnCreateContextMenu() method:

    public override void OnCreateContextMenu(
      IContextMenu menu,
      View view, 
      IContextMenuContextMenuInfo menuInfo) {
      base.OnCreateContextMenu(menu, view, menuInfo);
      MenuInflater.Inflate(Resource.Menu.Main_Options, menu);
    }
  3. Lastly, we can respond to item selections, as we did with the options menu, in the OnContextItemSelected() method:

    public override bool OnContextItemSelected(IMenuItem item) {
      if (item.ItemId == Resource.Id.action_refresh) {
        // do something here...
        return true;
      }
      return base.OnContextItemSelected(item);
    }

How it works...

We can provide a context menu for any view, but they are most often used for items in a list, grid, or other view collection. One way to show a contextual menu is to use a floating or pop-up menu, and it is the recommended way for apps supporting versions of Android below version 3.0.

Tip

If the views or list view is not registered with its activity or fragment, the context menu will not be displayed, even if the methods are implemented.

When the user long-taps on a view that has been registered for a context menu, the activity or fragment attempts to display a menu that is created or inflated in the OnCreateContextMenu() method.

After the user selects an item from the contextual menu, the OnContextItemSelected() method on the activity or fragment is invoked. In this method, we initiate the desired operation that was selected. We can identify the selected item using the ItemId property.

There's more...

Using the IContextMenu instance that is passed into the OnCreateContextMenu() method, we can change or remove the header of the popup menu. The header could be a combination of an icon and/or text or a separate custom view:

menu.SetHeaderTitle("My Context Menu Heading");

See also

  • The Creating an options menu recipe

  • The Creating contextual action mode menu recipe

 

Creating contextual action mode menus


The action bar provides the user with a set of actions; however, these actions are usually just the most commonly used. Sometimes, the context of the app changes, so the presented actions need to adjust to what is commonly used in the new context.

How to do it...

There are a few steps to implementing a contextual action bar:

  1. The first step is to implement the ActionMode.ICallback interface. This interface can either be implemented in a new, separate class or on the actual activity or fragment:

    public class MainActivity :
      AppCompatActivity, ActionMode.ICallback {
      public bool OnCreateActionMode(
        ActionMode mode, IMenu menu) {
      }
      public bool OnPrepareActionMode(
        ActionMode mode, IMenu menu) {
      }
      public bool OnActionItemClicked(
        ActionMode mode,IMenuItem item) {
      }
      public void OnDestroyActionMode(ActionMode mode) {
      }
    }
  2. In the OnCreateActionMode() method, we create the menu as we would any options menu:

    public bool OnCreateActionMode(ActionMode mode, IMenu menu) {
      mode.MenuInflater.Inflate(Resource.Menu.options, menu);
      return true;
    }
  3. Because we are not going to be updating the action mode once displayed, we can return false in the OnPrepareActionMode() method:

    public bool OnPrepareActionMode(
      ActionMode mode, IMenu menu) {
      return false;
    }
  4. We handle any item selections in the OnActionItemClicked() method:

    public bool OnActionItemClicked(
      ActionMode mode,IMenuItem item) {
      if (item.ItemId == Resource.Id.action_refresh) {
        // do something here...
        return true;
      }
      return false;
    }
  5. We don't need to do anything when we leave action mode, so we leave the OnDestroyActionMode() method empty:

    public void OnDestroyActionMode(ActionMode mode) {
    }
  6. An instance of ActionMode.ICallback is passed to the StartSupportActionMode() or StartActionMode() methods:

    someView.LongClick += (sender, e) => {
      if (actionMode == null) {
        // start the action mode
        actionMode = StartSupportActionMode(this);
        someView.Selected = true;
      }
    };

How it works...

The contextual action mode menu is actually a separate action bar-like UI element that overlays but does not replace the actual action bar.

Tip

Contextual menu items do not need to have the showAsAction attribute set in order to be displayed (it is ignored); by default, everything is visible.

This menu provides a set of commands that can be displayed based on some context, usually after a selection of an item on the screen. Selections are usually done after a long-tap, similar to traditional context menus; however, instead of a popup, the action bar is transformed. This provides a consistent interface without disrupting the flow of the task.

In order to enter action mode, we invoke the StartSupportActionMode() method. If we are not using the support libraries, we invoke the StartActionMode() method. This will return an ActionMode instance, which can then be used to customize the appearance of the action mode overlay.

When entering action mode, the OnCreateActionMode() method is invoked. Here we create the various action items that will be presented on the actions bar.

The OnPrepareActionMode() method is invoked whenever the action mode changes or is invalidated. This method allows us to optionally modify the UI. We must return true if any changes were made and false if nothing was modified.

When the user selects an action item, the OnActionItemClicked() method will be invoked. The current action mode and the selected item are provided so that we can perform the task.

There's more...

If we are using lists and supporting Android 3.0 and above, there is an extra feature that we can make use of: multiple selections. There is currently no native support for a similar functionality on older versions of Android; however, there is no reason why we can't use this feature on newer Android versions.

Implementing this requires a few extra steps but is actually an extension of the normal contextual action mode. Instead of implementing the ActionMode.ICallback interface, implement the AbsListView.IMultiChoiceModeListener interface (which actually derives from ActionMode.ICallback). This adds one extra method:

public void OnItemCheckedStateChanged(
  ActionMode mode, int position, long id, bool isChecked) {
  // handle item selections and deselections
}

And finally, we let the list view know about the multiselect availability by passing the instance. This is done instead of registering the context menu for floating menus:

listView.ChoiceMode = ChoiceMode.MultipleModal;
listView.SetMultiChoiceModeListener(this);

See also

  • The Adding action bar action items recipe

  • The Creating a contextual menu recipe

 

Sharing code with other platforms


One of the major reasons for using Xamarin.Android is the use of C# as the programming language. But this is not the only benefit as that same C# code can be shared with other platforms, such as iOS, Windows, or Mac OS.

How to do it...

First, we are going to create the project structure that we are going to use to create our cross-platform app. In this example, we will only target Xamarin.Android and the Console, but extra platforms can be added.

  1. Open Xamarin Studio or Visual Studio and create an empty solution. For example, we are going to call this one XamarinCodeSharing.

  2. In this solution, create three projects:

    • An Android project named XamarinCodeSharing.Droid

    • A console application named XamarinCodeSharing.Desktop

    • A portable class library named XamarinCodeSharing.Core

  3. Open the project settings for XamarinCodeSharing.Core. If you are using Xamarin Studio, navigate to Build | General. Or if you are using Visual Studio, navigate to Library and then click on Change under the Targeting section.

  4. Note the various platform options available, including iOS, Android, Windows, and several others, some with version options. Ensure that the .NET4.5 and the Xamarin.Android boxes are selected as these are the platforms we are going to need.

  5. To make things easier, we are going to use a NuGet package, Microsoft.Net.Http, which simplifies the process of using HTTP and REST services. Install this package into each of the three projects.

  6. Add a project reference from XamarinCodeSharing.Droid to XamarinCodeSharing.Core and a project reference from XamarinCodeSharing.Desktop to XamarinCodeSharing.Core.

  7. Now that we have our project structure in place, we are going to write some code that will access the web service, and then see how that code is reused without modification or even recompilation. What we are going to do next all takes place in the XamarinCodeSharing.Core project.

  8. To make things easy, we can just delete the file that the IDE created. Xamarin Studio created a file named MyClass.cs, and Visual Studio created a file named Class1.cs.

  9. We can now create a new class named BlogItem, which will represent the actual blog entries. This bit is very simple and is just a set of properties:

    using System;
    
    namespace XamarinCodeSharing.Core
    {
      public class BlogItem
      {
        public string Title { get; set; }
        public string Link { get; set; }
        public DateTime PublishDate { get; set; }
        public string Description { get; set; }
      }
    }
  10. In the same project, create another new class named XamarinBlog, which both represents the blog as well as provides a means to download the blog:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net.Http;
    using System.Threading.Tasks;
    using System.Xml.Linq;
    using System.Net;
    
    namespace XamarinCodeSharing.Core {
      public class XamarinBlog {
        private const string BlogUrl = "http://blog.xamarin.com/feed";
    
        // blog metadata properties
        public string Title { get; set; }
        public string Link { get; set; }
        public List<BlogItem> Items { get; private set; }
    
        // Download the feed, parse it and return a blog object
        public static async Task<XamarinBlog> Download() {
          HttpClient client = new HttpClient();
          HttpResponseMessage response = await client.GetAsync(BlogUrl);
    
          // if all went well, read the feed, otherwise fail
          if(response.IsSuccessStatusCode) {
            return await ParseResponse(response.Content);
          }
          else {
            throw new Exception("There was a problem.");
          }
        }
    
        // Read the response out of the content and 
        // create objects
        private static async Task<XamarinBlog>ParseResponse(
        HttpContent content) {
          XamarinBlog blog = new XamarinBlog();
    
        using(Stream stream = await content.ReadAsStreamAsync()) {
          XDocument doc = XDocument.Load(stream);
          XElement channel = doc.Root.Element("channel");
    
          // load the blog metadata out of the xml
          blog.Title = WebUtility.HtmlDecode(
          channel.Element("title").Value);
          blog.Link = WebUtility.HtmlDecode(
          channel.Element("link").Value);
    
          // load the blog items out of the xml
          var items = from item in channel.Elements("item")
          select new BlogItem {
            Title = WebUtility.HtmlDecode(
            item.Element("title").Value),
            Link = WebUtility.HtmlDecode(
            item.Element("link").Value),
            PublishDate = DateTime.Parse(
            WebUtility.HtmlDecode(
            item.Element("pubDate").Value)),
            Description = WebUtility.HtmlDecode(
            item.Element("description").Value),
          };
          blog.Items = items.ToList();
        }
    
        return blog;
        }
      }
    }

    There are several important points to note here. We are using the async and await keywords to make asynchronous code easier to read, something which is not available in Java. Another feature is LINQ to XML to make working with XML easier to parse, another feature not available to Java. And finally, WebUtility.HtmlDecode is used as all the data is HTML encoded inside the XML.

Now that we have created the main logic of the app, we can look at those native implementations. First, we will create the Console app that will run on almost any desktop operating system, such as Windows, Mac OS, and most of the flavors of Linux:

  1. To do this, we can just replace the code in the Program.cs file with the following:

    using System;
    using XamarinCodeSharing.Core;
    using System.Threading.Tasks;
    
    namespace XamarinCodeSharing.Desktop {
      class MainClass {
        public static void Main(string[] args) {
          GetBlogItems().Wait();
    
          Console.WriteLine("Press any key to quit.");
          Console.ReadKey();
        }
    
        private static async Task GetBlogItems() {
          Console.WriteLine("Downloading blog...");
          XamarinBlog blog = await XamarinBlog.Download();
          Console.WriteLine("Download finished.");
          Console.WriteLine();
    
          Console.WriteLine("{0} ({1} items)",
          blog.Title, blog.Items.Count);
    
          foreach (var item in blog.Items) {
            Console.WriteLine(item.Title);
            Console.WriteLine(
              item.PublishDate.ToString("d MMMM yyyy"));
            Console.WriteLine(item.Description);
            Console.WriteLine();
          }
        }
      }
    }

If we run the desktop project now, the console will start up, download the blog feed, and then display each entry along with a short summary. Last but not least, we want to get that mobile version going. And what better platform to support first than Android?

  1. Switching to the Xamarin.Android project, we can replace the code in the MainActivity.cs file with the following:

    using System.Collections.Generic;
    using System.Linq;
    using Android.App;
    using Android.OS;
    using Android.Runtime;
    using Android.Widget;
    using XamarinCodeSharing.Core;
    
    namespace XamarinCodeSharing.Droid {
      [Activity(
        Label = "XamarinCodeSharing.Droid", 
        MainLauncher = true, 
        Icon = "@drawable/icon")]
      public class MainActivity : ListActivity {
        private const string TitleKey = "title";
        private const string SubtitleKey = "subtitle";
    
        protected async override void OnCreate(Bundle bundle) {
          base.OnCreate(bundle);
    
          var progress = new ProgressDialog(this);
          progress.SetTitle("Downloading blog...");
          progress.SetMessage(
            "Please wait while we download the Xamarin blog...");
          progress.Show();
    
          XamarinBlog blog = await XamarinBlog.Download();
          var items = from item in blog.Items select new JavaDictionary<string, object> {
            { TitleKey, item.Title },
            { SubtitleKey, item.Description }
          };
    
          ListAdapter = new SimpleAdapter(
            this,
            items.Cast<IDictionary<string, object>>().ToList(),
            Android.Resource.Layout.SimpleListItem2,
            new []{ TitleKey, SubtitleKey },
            new []{ Android.Resource.Id.Text1, Android.Resource.Id.Text2 });
    
          progress.Dismiss();
          progress.Dispose();
        }
      }
    }

If we run this Android app now, we shall get that app that downloads the latest Xamarin blog posts and displays them in a neat list.

How it works...

Portable class libraries is one of the most important aspects of code reuse. Although there are many different ways to reuse code, such as file linking or shared projects, none can match the reliability and ease of simply reusing the compiled assembly. This assembly can be tested and verified and then used and reused without fear of problems arising on different platforms.

Why? It is because each platform in each portable class library profile promises to support all the features, for all platforms, in that profile, and all those features function exactly the same.

Using Xamarin.Android, we now have all the features of the .NET runtime available, the same runtime that runs on almost all devices. Along with that same runtime, we can now build libraries that run on that runtime, and those libraries will run on all platforms that have the same runtime. Those platforms include iOS, Android, Windows Phone, Mac OS, Windows, Linux, and even more, such as PlayStation!

Although we can never achieve 100 percent code reuse, as each platform has differences (especially in the user interface), much of the code lives below the surface and can be reused. And using the commonality of the runtime and languages, we can create abstractions that can work around the platform differences, resulting in even more code reuse.

Although we only covered two platforms in this example, we can already see that it takes more code to work with the data than it does to display it. Adding extra platforms, such as Windows Phone and iOS, will result in this ultra-simple example app being able to support the major mobile operating systems, with the only difference being the UI.

About the Author

  • Matthew Leibowitz

    Matthew Leibowitz is a professional software engineer living in South Africa, and is currently working in a Xamarin development team. He has many years of professional experience as a programmer in developing systems ranging from servers, to desktops, to mobile devices.

    He has a passion for programming and has recently been awarded Xamarin Certified Mobile Developer certification for his work. He has written various articles on his blog and has participated in several forums.

    With his experience and great passion for development, Matthew spends his days continually looking for new ways to create a better experience for users and other developers. Some of his work is seen on GitHub under the username mattleibow. In addition to his public code, Matthew is active on Twitter with the same username.

    Browse publications by this author

Latest Reviews

(1 reviews total)
Muito bom e bem organizado os conteúdos.
Book Title
Access this book, plus 7,500 other titles for FREE
Start FREE trial