Tuesday, February 26, 2013

Adding images to TextView and EditText using Spannables in Mono for Android

I've just been playing around with Spannables in an attempt to help out a user on the Xamarin Forums, his topic is "Text With Image". Just from looking at that topic name, I thought: "Hey, he probably just want to show an image next to some text or something, this should be easy enough". Then I looked inside, and they guy actually wanted text inline with text when actually editing it. Now I thought: "How do I do that?!"
I think I have touched the concept of Spannables briefly before, when I helped a guy making a sub-part of a text bold or something, but I never thought they could be used for displaying images inline with text. I guess this is how it is done in all those messaging apps, which show emoticons. I decided to use that as a sample.

I started out with a super simple sample trying to get an Image shown in a TextView. I googled up some solutions and sure, Spannables allow using ImageSpan inside of them! There were nice samples and such, and I came up with this.
Easy, huh? And you can add loads of other Spans to the Spannable, such as StyleSpan, which you can style your fonts with bold, italic and other styles.

Since that was so easy, I quickly tried to do that with an EditText. It also works just fine, so moving on. How do I imitate those messaging apps, which replace ":-)" with an actual smiley. Now EditText has some nice events which you can listen to for changes. I listen for AfterTextChanged, from here I can get the Editable Property from the argument, which is essentially a Spannable you can edit and the changes will be reflected in the EditText. This is probably a good place to replace text with images.
Next I cooked up a class which holds a Dictionary of strings and ints. The string keys are the text representation of the smileys, i.e. :), :-), :D, :P and so on. The ints are the Android Resource ids for the Drawables representing the smileys. Then I have a method for replacing all the matches in the string with their respective Drawables. It looks like this.
Now you might notice I am removing all the images if they are present. This is because it is not possible to have two Spans at the same index in a Spannable, hence they need to be removed. Don't worry all the images are added at the end. This simply loops all the string matches in the Spannable and adds ImageSpans for the matches. Very simple. To get all the indices in a string which match I use a simple extension I found on StackOverflow.
Now the AddSmiles() method is hooked up to the AfterTextChanged event for the EditText, and voila. Text is replaced with images!
Pretty awesome smileys :-D 
The complete sample code can be found in this Gist: https://gist.github.com/Cheesebaron/5034440

You can also watch this video for a demonstration

Saturday, February 23, 2013

Using Dialogs in Mono for Android

Using Dialogs in Mono for Android is very similar to what you do when writing Java code for Android. But maybe let us first briefly look into what we can use Dialogs for. There are several things they are really useful for:
  • Showing Alerts - The user gets notified about something important happening in the application, or the application failed. You might know the Alert Dialog, which shows when an application becomes unresponsive and you get the choice to either Wait or Force Close the application.
  • Selecting a values from lists - The user chooses a field and gets presented with a short list of choices. This could be for instance that you are already showing another dialog, where you want the user to write his username and password, but additionally you want the user to choose a server from a list of the available ones, this could get presented in a new dialog.
  • Adjusting settings - For instance when you have to adjust the brightness of your screen on your phone, you are shown a dialog with sliders for adjusting the brightness. This is also the case for volume etc.
  • Picking a Date or Time - This is used widely in Alarm clock and calendar applications.
There are probably many more uses, but I think you get the idea about the use of Dialogs and what they are good for. If you notice the pattern, Dialogs are made for making the user take an action. What are Dialogs less good for? I highly recommend not using them for progress indications. Taking away the focus from the app to show a Dialog with a Progress Indicator is not good use, you should rather, if possible, show a ProgressBar or Activity Indicator in your view, and let your user navigate around your application, to be able to do something else in your application while they wait for the other task to end. This could be uploading a file to a server, people do not want to wait and watch a ProgressBar in a Dialog and not being able to do anything else, they will get bored quickly.

Before we get our hands dirty in code let me explain the two methods to create Dialogs. One is you create it inline of the code where you need to show it. That could be in an EventHandler for a Button. Another way is to use the OnCreateDialog methods in an Activity, however note that these were Deprecated in API level 8 and 13 when Fragments were introduced. The instantiation of a Dialog has not changed. It is recommended to use a DialogFragment in API level 13 and above which I will cover at a later point in this blog post.

Dialogs in Activities

Get the sample code here!

Now that is covered why don't we get our hands a bit dirty with some code samples? The first couple of samples are going to show what the default Dialog classes can show without using custom views inside, then some more advanced stuff will be shown. Also the first samples will use the old style of creating Dialogs inside activities, and the last samples will show the DialogFragment introduced in API level 13.

This first sample shows how to create a simple Yes/No type of dialog, which shows when a user presses a button. I use an AlertDialog.Builder to create this dialog, and you will see this approach used throughout the samples. An AlertDialog has loads of properties which can be set, such as the title, messsage, negative button and positive button. Here a message is set, the negative and positive buttons. The EventHandlers are empty in this sample, but could be used to do an action in your application. When using AlertDialog.Builder you need to call Create() at the end to get the actual AlertDialog instance, which then can be shown by calling Show(). The resulting dialog can be seen in Figure 1.
Figure 1 - Simple Yes / No Dialog

Now lets look at how to create an Alert type of Dialog, screenshot can be seen in Figure 2, with an icon and title and a couple of buttons. Notice how this time I am calling ShowDialog inside the Click Event and how I have consts defined in the top of my class. This is due to the int id which is passed in ShowDialog is the same id which is passed as argument in OnCreateDialog where I create my dialogs, which is the pattern used pre API level 13.
This kind of Alert Dialog can of course also have some description text which is simply set with the SetMessage() method.
Figure 2 - Alert Dialog
Now let us try something more exciting. Let us make a dialog with an item you can select from a list.
Figure 3 - List Dialog
The AlertDialog class has a nice method SetSingleChoiceItems which takes a list of items either from Arrays.xml or a an array of items. You also need to provide it with an EventHandler for what happens when an Item in the list is selected. Otherwise it is the same approach as the other two Dialogs shown. Instead of using lambda expressions for the Event Handlers for the positive and negative buttons you can also make methods for handling the events. The result of this dialog can be seen in Figure 3.

AlertDialog also has a nice method for making Multiple Choice Dialogs, so it shows a list of items which have checkboxes. This is done by giving the method SetMultiChoiceItems an array of items either from Resource or an instance, you can choose which items are checked or not and lastly add an Event Handler for handling which items are chosen.
Figure 4 - Multi Choice List Dialog
You might also have noticed that I've passed a second argument to the AlertDialog.Builder, which actually allows you to set the theme of the Dialog, in this case it sets the theme to Holo Light, which can be seen in Figure 4, this can be done when using API level 13 and above. But again, very simple stuff!

Final example shows how to make a Dialog with a custom view inside of it. Approach is exactly the same as with the other examples, however this time I use the SetView() method of AlertDialog to set the custom view, which I have inflated. The OnClicked handler also shows you how to get the data from the elements in custom view.
Figure 5 - Custom View Dialog
So what happens in the OkClicked Event Handler, is that it conveniently receives the AlertDialog in the sender object, which we can use to find all the views contained in it. This allows us to simply use FindViewById to find the two EditText's contained in the custom view which were set.

Dialogs in Fragments

You might think that this is all to know about Dialogs, but sorry there are still some stuff to cover. I've pointed out that some methods were deprecated in API level 8 and 13, and a new pattern was introduced around that time called Fragments. Creating Dialogs in Fragments is slightly different that in Activities; hence I will show you two examples on how that is done. However creating the actual Dialog is still done with AlertDialog, but I will also show you one of the built in Dialogs in Android.
Lets just dive into the code!
This is a very simple dialog inflating a view with a couple of buttons. Their Click events are set to instantiate a some dialogs, which are not shown. But this approach is the way you show Dialogs when using Fragments. Actually you are displaying DialogFragments. It also implements a couple of listeners for the two different Dialogs which I will show you now.

Figure 6 - DatePickerDialogFragment
For the DatePickerDialogFragment, we are lucky that Android actually have a DatePickerDialog implemented already which just needs to be wired up to a listener and set a date inside of it. The listener allows us to listen for date changes in the Dialog. Using a DialogFragment requires you to create a Dialog inside of OnCreateDialog. That is it, here you can create all the Dialogs I have shown you in the previous samples with the AlertDialog.Builder, you just have to create these DialogFragments, instead of putting them into Activities OnCreateDialog(). The DatePickerDialogFragment can be seen in Figure 6.

Just to show another example, let us create a Custom View DialogFragment, which allows you to pick a number from a NumberPicker, see Figure 7.
Figure 7 - NumberPickerDialogFragment

Now you have seen a lot of different Dialogs, both using the old deprecated Activity approach and the newer Fragment approach. The entire sample can be seen in my GitHub repository for this blog post.