StickyScrollView for Xamarin Android

ScrollViews are pretty useful when there is more content than space to display it. But through scrolling chances are high that the user loses track of context or title of the section, so it’s nice to have a sticky header/title that always stays at the top of the ScrollView.

Emil Sjölander created such a control (https://github.com/emilsjolander/StickyScrollViewItems/) for Java Android projects so I decided to port the control to C#. https://github.com/maltegoetz/StickyScrollViewXamarinAndroid

sticky22

The repository contains an example project with a simple StickyScrollView that has a LinearLayout with a few colored FrameLayouts children. One on the FrameLayouts is sticky.

Usage

Usage is pretty easy, you just need to copy the StickyScrollView.cs file to your project and the Attrs.xml file to the values folder of your project.

Replace the ScrollView with a StickyScrollview. From this:

<ScrollView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_height="match_parent"
  android:layout_width="match_parent">
    <!-- scroll view child goes here -->
</ScrollView>

to

<namespacelowercase.StickyScrollView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_height="match_parent"
  android:layout_width="match_parent">
    <!-- scroll view child goes here -->
</namespacelowercase.StickyScrollView>

The StickyScrollView inherits from ScrollView so you can only add one child but the child can have some more children. In this example I used a LinearLayout with a few views. One or more children can have an android:tag attribute with the value sticky, these will stick at the top of the ScrollView.

<namespacelowercase.StickyScrollView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/sticky_scroll"
  android:layout_height="match_parent"
  android:layout_width="match_parent">
    <LinearLayout
      android:layout_height="match_parent"
      android:layout_width="match_parent"
      android:orientation="horizontal">
        <!-- other children -->
        <View
          android:layout_height="300dp"
          android:layout_width="match_parent"
          android:tag="sticky"/>
        <!-- other children -->
    </LinearLayout>
</namespacelowercase.StickyScrollView>

There are also two additional flags that can be set on views that were added to optimize performance for the most usual cases. If the view you want to stick either has transparency or does not have a constant representation than you must supply one or both of the following flags. -hastransparancy for views that have transparancy and -nonconstant for views that will change appearance during there sticky time (examples are buttons with pressed states as well as progress spinners).

So this ends up with 4 different ways to tag a view as sticky resulting is slightly different behaviour android:tag=“sticky“android:tag=“sticky-hastransparancy“ android:tag=“sticky-nonconstant“ and android:tag=“sticky-hastransparancy-nonconstant“.

Werbeanzeigen
StickyScrollView for Xamarin Android

Notifications on iOS 1/4: Local Notifications

Notify All The Things!

img0_notify

Notifications give us as App Developers a great opportunity to extend our App’s appearance beyond its actual frame.

In this 4-part series we will have an in-depth look on Notifications on iOS.

We can provide the user with informations that are important right now; even, if the App is currently not running.

Think about building a chat App: You want to notify the user when a new message arrived. Building a ToDo App? You surely want to send a reminder when a task is due.

iOS knows 3 kinds of Notifications:

– Local Notifications: A Notification which is triggered by the App. A Local Notification can be scheduled in advance. For example you can preset a Local Notification to fire when a user created a new ToDo Item with a due-date in your App. We will talk about Local Notifications in Part 1 and Part 2.

– Remote Notifications: A Notification which is triggered by your server. The advantage: You are completely flexible in when/what/why you fire a Notification. The drawback: You need your own server. Another drawback about standard Remote Notifications is that Apple neither guarantees you, that the Notification will be delivered nor informs you if so. To learn more about Remote Notifications check out Part 3 of this series.

– VoIP Notifications: VoIP Notifications are an important addition if you develop an App with VoIP functionality: Most important Apple guarantees you that a VoIP Notification will be delivered to the target Device. Furthermore you’ll enjoy an increased message size threshold. Last but not least your App on the device will be notified once the notification arrives. No notification will be automatically shown to the user! So you have time to do some background work and fire a local notification after you connected to the caller for example.

So, let’s start by having a look on Local Notifications!

First things first

Let’s start by creating a blank single view iOS App.

Don’t forget to give the app an unique name and Organisation Identifier since this will become relevant when we’ll take a look at remote notifications in Part 3.

Before we implement the actual notifications we have to decide what kind of notifications we want to show.

We can choose between (or combine)

– Banner: A small banner which appears on top of the screen for a few seconds, on the Lock Screen and in the Notification Center.

thumb_IMG_1232_1024

We can provide up to two additional actions for a Banner.

– Alerts: An AlertView showing outside the context of the actual Application (e.g. on the home screen). An Alert requires an action by the user. We can provide up to four Actions for an alert.

– Badge: A small, red circle on the top right corner of an App Icon, displaying the number of notifications by this App.

thumb_IMG_1233_1024

We can play an optional sound when we trigger any of the above notifications.

Coding time!

In Part 1 we will focus on Local Notifications, featuring Banner, Badges and Sound.

Before we are allowed to send out a Notification we have to ask the user for permission if we run on iOS 8.0 or above. In the “FinishedLaunching” Method of our AppDelegate we past the following:

if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes (
UIUserNotificationType.Alert
| UIUserNotificationType.Badge |
UIUserNotificationType.Sound, null
);

application.RegisterUserNotificationSettings (notificationSettings);
}

In this snippet we check if we are running on iOS 8 or higher first. After this we utilize UIUserNotificationSettings to get a NotificationSettings object. We can pass a combination of all UIUserNotificationTypes we want to use. In our example those are Alert, Badge and Sound. The first time we call RegisterUserNotificationSettings a AlertView will be shown to the user asking, if he wants to allow our App to send Notifications.

thumb_IMG_1231_1024

Now we are ready to send our first notification!

To do so, we will create a Button in our Storyboard. Name this Button “btNotify”.

In our ViewControllers ViewDidLoad() Method paste this snippet:

notify.TouchUpInside += (sender, e) =>
{
//New Notification
var notification = new UILocalNotification();

// Set FireDate
notification.FireDate = NSDate.FromTimeIntervalSinceNow(10);

// Set Message
notification.AlertAction = "Hello Badge";
notification.AlertBody = "Look! A Notification!";

// schedule it
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
};

Don’t forget to import Foundation since we are using NSDate.
In this Snippet we create a new UILocalNotification, set the FireDate, Title and Message and then fire it. It should now look like this when we click the Button:

thumb_IMG_1232_1024

That’s it! We’ve sent our first Notification! Yey!

Important note: Notifications won’t be shown if you are still inside the App. Notifications will only be displayed if your App is in the background. We will talk about this behaviour in a second.

Now we want to complement our Banner with a Badge. To do so we simply add notification.ApplicationIconBadgeNumber = 1; in our notify.TouchupInside Event.

After clicking the button now and leaving the App you should now see a Badge on your AppIcon as well as the Banner popping up.

Fell free to add a sound which will play when the Notification is fired by setting a SoundName: notification.SoundName = UILocalNotification.DefaultSoundName;.

But what happens, if the Notification is fired while the App is in the foreground? As we learned before the OS won’t display anything in this case. So we have to handle this by ourselves.

Fortunately iOS makes it easy to handle this by providing ReceivedLocalNotification which we can implement in our AppDelegate. Let’s switch back to this and add this code into your AppDelegate.cs:

public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
UIAlertController okayAlertController = UIAlertController.Create (notification.AlertAction, notification.AlertBody, UIAlertControllerStyle.Alert);
okayAlertController.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Default, null));
Window.RootViewController.PresentViewController (okayAlertController, true, null);

UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
}

And that’s it for receiving Notifications while in the App!

We just create an AlertController, pass in the Informations from the passed UILocalNotification object and reset the App’s badge.

One more thing

As stated before you can provide a custom sound which should play when your Notification is fired. If you don’t want to stick with the default System Sound you can provide your own sound. The sound file which you have to include in your App Bundle can have a maximum length of 30 seconds. CAF and AIFF files are allowed. If you have installed XCode you can utilise afconvert to convert sound files:

afconvert -f caff -d LEI16@44100 -c 1 input.mp3 output.caf should do the job. You can then specify the custom sound by referencing it: notification.SoundName = "Sound/output.caf";

Next up

In this post you’ve learned which kinds of Notifications exist on iOS. We learned how to schedule Local Notifications and how to customise them.

In Part 2 we will see how Badge Notifications can be even more customised with custom Actions and how to handle App Launches from Notifications.

Notifications on iOS 1/4: Local Notifications

The ViewModel method template

ViewModels are the DDD equivalent of application level services and have two basic three basic responsibilities:

  • Start and manage domain level workflows and transactions.
  • Keep track of the state of the current view (or event the complete application).
  • Translate domain objects and states into a representation that can be displayed by the view.

Over time, we got to some standard for methods on ViewModels, that resulted in a template methods that handle „everything“, and we can then just pick the things we need.

As many Apps represent some server data, ViewModels tend to have a certain set of methods:

  • LoadData/Activate():
    Called every time, a View loads with the ViewModel as it’s datacontext. It makes sure all data is loaded correctly.
  • UpdataDataItems():
    Loads all data, that is currently available.
  • Refresh():
    Refreshes data from the web.

(Yes, these are quite similar to MvvmCross’s init(), start() and reloadState() methods.)

LoadData()

LoadData() is called when a view loads a ViewModel as it’s data context. This methods fill itself with data and (when required) starts a refresh to get the latest and greatest data from some service.

This is also the place to take on parameters that are submitted by the view loading this model.

public async Task LoadDataAsync()
{
    if (!IsDataLoaded)
        await UpdateDataItemsAsync();

    if (NetworkHelper.IsNetworkConnectionAvailable && UpdateTimerHelper.ShouldUpdate("Employees"))
        await RefreshAsync();
}

UpdateDataItems()

This is the common place to pick up all data that is already available: Locally cached items.

Loading the first data is intended to be fast. Is should be available almost at an instant, so the user has something to view and interact with, while the update operation starts in the background.

private async Task UpdateDataItemsAsync()
{
    // Get items from local cache
    var employees = (await _employeeService.GetEmployeesAsync()).OrderBy(e => e.Sorting).ToList();
    Employees = new ObservableCollection<Employee>(employees);

    IsDataLoaded = true;
}

Refresh

Refresh() is actually the first real operation of the ViewModel. Like most methods on ViewModels, it does not have a return type except Task. Usually, they are called from some event handler (like button clicks) which are void returning and therefore cannot really await anything. Updates happen via the INotifyPropertyChanged anyway.

ViewModel methods should never throw exceptions (see: [The exception barrier]). That’s why most of our ViewModel methods look like this:

public async Task RefreshAsync()
{
    // Precondition check
    if(IsDataLoading) return;
    IsDataLoading = true;

    // Preparations
    var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
    
    try
    {
        // Run the actual operation
        await _employeeService.RefreshAsync(cts.Token);
        await UpdateDataItemsAsync();

        UpdateTimerHelper.SetUpdate("Employees");
    }
    catch (HttpRequestException)
    {
        _notificationService.Notify(ApplicationConstants.Text_NoInternet);
    }
    catch (OperationCanceledException)
    {
        // Cancelled because of timeout
        if (cts.IsCancellationRequested)
            _notificationService.Notify(ApplicationConstants.Text_Timeout);
    }
    catch
    {
        // Just to annoy developers, until they got all their error cases checked.
        System.Diagnostics.Debugger.Break();
    }
    
    IsDataLoading = false;
}

This is an „all-in“ example:

  • Before running the methods, application level preconditions are validated: Are we updating already?
  • Preparations like task extenders, CancellationTokens, etc. are made.
  • The actual method gets executed.
  • All error cases get handled.
We usually put an extra ´Debugger.Break()´in the last catch clause. This shouldn’t activate at all, but if it does, the developer knows he has some unmatched error cases. Hopefully, it is annoying enough to bring him to handle it. :)
The ViewModel method template

Architecture in cross platform projects: Overview

When you start reading into Mvvm, you usually find some articles about INotifyPropertyChanged, Bindings, Commands and reducing Code Behind. Once you are past that point, information gets rare.

But there’s a lot more to Mvvm than just these basic concepts. Especially, if you want to span that architecture cross platform with Xamarin.

This series explains a reference architecture for cross platform Mvvm, which we used in several projects. In the coming weeks, I am going into details for all steps along the road.

It all began in the model…

Add a PCL: Project.Sample.Domain

We usually start with the domain model for our app (yes, we used DDD, but even if you don’t’ this is a good starting point). First step is to create C# classes for all of our domain entities like News, Users, Products or whatever there is. These tend to be just dumb classes with a bunch of getters and setters for most cases.

Once we’ve got the things we work with, we start wrapping them some services around them that know how to obtain these models and how to perform operations on them. Until now, our project looks somewhat like this:

xplat_architecture_1_ model

Further reading:

  • [Design considerations for the domain model.]

And then, things got connected…

Add a PCL: Project.Sample.Domain.RestApi

Next, we connect our app to the services. In most cases, these are already in place: Instagram Api, Office 365 Api, some Azure Mobile Service, etc.

What we have to add are the clients, that connect to these services and convert between their data transfer objects and our model. This usually involves Json.Net, HttpClient and a lot of .FromJson() methods.

This is also the point in time to write some integration tests to see if your clients work correctly. Doing that now spares a ton of debugging time later.

xplat_architecture_2_connectivity

Further reading:

  • [Design considerations for service connectors]

Adding some state…

Add a PCL: Project.Sample.Infrastructure

It’s about time we start making a real application out of all those connected services and models we got right here. So now we got to stop thinking in domain terms and move over to application design (no, not those fancy UI stuff yet; but getting close!).

View Models are the next wrapper around our domain: They know how to uses the services, how to handle all the exceptions (yes, ALL of them) and besides that, they hold the “state” of the application.

State means, they know what data needs to be loaded, what has been loaded already, where we can go and what we can do from where we are. Despite of having just such a small box in the architecture diagram, the ViewModels are our real champions.

xplat_architecture_3_viewmodels

Further reading:

 

Fine, can we do Android now?

Add: Project.Sample.Clients.AndroidApp, Project.Sample.Clients.WindowsApp, …

NO! Do windows first. It’s much easier and way more fun. But yeah, this is where you add all your client projects.

We’ve come pretty far already, but clients still have a lot of duties: They provide configuration for all the models, viewmodels, services, clients, etc.; They have to connect the UI with the viewmodels and of course they contain the UI itself.

All that UI stuff are left uncovered here, because when using Xamarin, you are just writing native code with camel cased naming.

Client projects consist of 3 parts:

  • The UI with all its Activities, ViewControllers, etc.
  • Platform specific implementations of interfaces required by all the underlying components.
  • Connectors to interact with viewmodels
xplat_architecture_4_clients

 

Configuration for the services is usually done using a dependency injection container and a service locator.

As connectors, you use Xaml bindings on windows and everything is nice and easy. Value converters are also a part of these connectors. You can use a framework like MvvmCross (mvx) to get something similar to bindings on other platforms as well.

If you won’t or can’t use Mvx, looking at windows’ compiled bindings (aka x:Bind) is a good option: It isn’t exactly human readable, but you can easily write something similar for android and iOS when getting down into their ListAdapters an ViewControllers.

Further reading:

  • [Learn from Xaml’s compiled bindings]
Architecture in cross platform projects: Overview

Drawer Navigation for Xamarin Android

Android has three different navigation patterns: stack navigation, tab navigation and drawer navigation.  Stack and tab navigation are pretty self-explaining, but the drawer navigation is a bit more complex. It enables you to add a panel with the main navigation options to the left edge, that is hidden most of time but revealed when swiping from the left edge to the right on the screen or by tapping the menu button in the top left corner.drawer1 drawer2

In the following part I will describe how you can add a DrawerLayout with Fragments that load when the user taps a navigation option. To implement this, we need to add the Android Support Library v7 AppCompat from the Component Store.

After adding this we need to create a new layout for the page with a DrawerLayout that has two child elements. The first child is the main content of the page, in this case we want to load fragments so we need to add a FrameLayout. The second child is the menu panel with the navigation options, a ListView is absolutely fine for that.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/drawerLayout"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
    <!-- Your main content -->
    <FrameLayout
      android:id="@+id/frameLayout"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />
    <!-- ListView with navigation options -->
    <ListView
      android:id="@+id/drawerListView"
      android:layout_width="240dp"
      android:layout_height="match_parent"
      android:layout_gravity="start"
      android:choiceMode="singleChoice"
      android:background="?android:attr/windowBackground" />
</android.support.v4.widget.DrawerLayout>

After adding the layout, we need to add the menu button to the ActionBar:

_drawerLayout = FindViewById<DrawerLayout>(Resource.Id.main_drawerLayout);
_drawerToggle = new ActionBarDrawerToggle(this, _drawerLayout,
    Resource.String.DrawerOpenDescription, Resource.String.DrawerCloseDescription);
_drawerLayout.SetDrawerListener(_drawerToggle);
ActionBar.SetDisplayHomeAsUpEnabled(true);

For the Toggle Descriptions we need to add two strings to your Resources/values/Strings.xml file:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="DrawerOpenDescription">Open navigation drawer</string>
    <string name="DrawerCloseDescription">Close navigation drawer</string>
</resources>

We need to make sure that clicks on the ActionBar will be forwarded if the ActionBarDrawerToggle is clicked, so we need to override the OnOptionsItemSelected method.

public override bool OnOptionsItemSelected(IMenuItem item)
{
if (drawerToggle.OnOptionsItemSelected(item))
	return true;
	switch (item.ItemId)
	{
		default: break;
	}

	return base.OnOptionsItemSelected(item);
}

The user will be able to navigate to different fragments so I added to arrays, one Array for the Fragments and another one for the titles:

Fragment[] fragments = new Fragment[] { new TopRecipesFragment(),
    new CategoryPastaFragment(), new CategoryRiceFragment(),
    new CategoryDessertFragment() };
String[] titles = new string[] {"Top Recipes", "Pasta",
    "Rice", "Dessert"};

For the navigation ListView items you need a layout, I called it NavigationOption.axml and only added a TextView, that should be enough for this demo:

<?xml version="1.0" encoding="utf-8"?>
<TextView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/navOptionTextView"
  android:layout_width="match_parent"
  android:layout_height="?android:attr/listPreferredItemHeightSmall"
  android:gravity="center_vertical"
  android:paddingLeft="16dp"
  android:textAppearance="?android:attr/textAppearanceListItemSmall"
  android:background="?android:attr/activatedBackgroundIndicator" />

After adding the layout, we can fill the ListView with some navigation options that the user can choose from later on and you need to add an event handler to navigate to another fragment.

drawerListView = FindViewById<ListView>(Resource.Id.drawerListView);
drawerListView.Adapter = new ArrayAdapter<string>(this,
    Resource.Layout.NavigationOption, Resource.Id.navOptionTextView,
    titles);
drawerListView.ItemClick += (object sender,
    AdapterView.ItemClickEventArgs e) => NavigateToFragment(e.Position);
drawerListView.SetItemChecked(0, true);
NavigateToFragment(0);   

The navigation to a fragment is implemented in the NavigateToFragment method, that will take a position (from fragments array) to navigate to the corresponding Fragment and display the proper title.

void NavigateToFragment(int position)
{
	base.FragmentManager.BeginTransaction().Replace(
             Resource.Id.frameLayout, fragments[position]).Commit();
	this.Title = titles[position];
drawerLayout.CloseDrawer(drawerListView);
}

That’s it, we now have a pretty awesome DrawerLayout navigation that is useful in many different scenarios.

Drawer Navigation for Xamarin Android