Filtering ListView with SearchView in Xamarin.Android

|
I recently made a video describing how to add a SearchView to your ActionBar, using the Support v7 package to provide backwards support, all this done in Xamarin.Android! I posted it on the Xamarin Forum's, University section, which I have access to, since I am attending Xamarin University. There were some interesting questions, which I found solutions for and I simply wanted to share them, so I am writing this blog post to do so. For background knowledge take a look at this video, which started this, and I am going to use that as a starting point for this blog post.


So the video, shows a very simple implementation of SearchView, which filters simple string elements feeded into the ArrayAdapter, which already has a nice simple Filter implementation, which simply matches the search query to see if it is contained in the items in the ListView. Now this simple implementation might not be sufficient enough for you, because as soon as you need to show something more complicated in a ListView, you will need to implement your own Adapter. Doing so will also require you to implement your own Filter as the Adapter you implement yourself cannot know what arbitrary data you will present.

SearchView filtering ArrayAdapter

Anyways, enough talk, let us dive into the code. So easy mode as described in the video and gist:

So here the magic happens in the OnCreateOptionsMenu method line 39-58, where we find the ActionBar MenuItem and subscribe to the SearchView's ActionView query changes, which invokes the default Filter in the ArrayAdapter.

Reacting on SearchView Expand/Collapse

One of the questions that popped up was, when having the back Action enabled in the ActionBar when using the SearchView, how do you react to the Expand and Collapse events? This is pretty simple, but might not be that super obvious.

You have to create a class implementing IOnActionExpandListener. In this example I am going to remove the filter from the Adapter when collapsing the SearchView.


To hook it up to the SearchView you have to use the helper class MenuItemCompat, to attach it to the MenuItem which you do in the OnCreateOptionsMenu:

Filtering in custom Adapters

Now the other question was, how do I filter my custom Adapter? Very good question if you ask me. As already mentioned, for that you have to implement your own Filter, as the nature of a custom Adapter is that you present custom stuff. Hence the default Filter implementation cannot know how to filter that. I am just going to replicate what the default Filter does on a string property of the model I am going to present in the ListView.

The final solution can be found on → GitHub

So before we begin I have to warn you that FilterResult which is used to store the filtered values temporarily, expects that the object stored is a Java type. So either your model which you populate your Adapter with has to implement Java.Lang.Object or you will have to wrap your values. I will show you the latter, as it will apply to the more use cases, as you probably cannot and probably do not want to implement Java.Lang.Object in your contracts or whatever you are using to store data in, especially when you are communicating and sharing code between platforms.

To wrap up .NET types with a Java type I am using modified code from this monodroid mailing list thread, which looks like this:




The main difference is that the Java holder object is disposed of immediately when it is converted to a .NET object. Also the comparison in the original source, whether the value was null is unsafe, as it does not take value types into consideration. The object disposal is very useful to keep GREF references down to a minimum. I really don't want the app to run high on memory.

Now with that covered, let us get to the actual Adapter and Filter. I have created a class called Chemical, which has Name and DrawableId property. Which are going to be assigned to a custom view, in the Adapter. Not going to cover View creation here, but this one is pretty simple, really.

So Chemical looks like this:

And the Adapter looks like this:


So I am just going to describe what happens in the custom ChemicalFilter, as the rest of the Adapter is pretty trivial. So first thing is that I have to pop in the reference to the ChemicalsAdapter, because I want to store both the original list of Chemicals and the filtered version in the Adapter, so we always can go back to the state we started at. So I always look for matches in the _originalData field, which is looped and matched, lower case, if the Chemical contains anything in the ICharSequence which is passed into the PerformFiltering method. The ICharSequence is just a spartan Java interface providing some simple methods such as lenght, getting a char at at specific position and a sub sequence of chars, nothing too fancy. I simply convert that to a string and match against the Chemical Name property. So the results of that matching is transformed into an array of Java objects, with help of the modifier .NET to Java wrapper I described above using a bit of LINQ. This is done since FilterResults expects an array of Java objects. I also call Dispose on the ICharSquence, as it seems like not doing so builds up the GREF count.

Now in PublishResults the values are converted back to the Chemical .NET type also using a bit of LINQ. The results are set in the Adapter's _item field and the Adapter is notified of the changes in the data set. Both arguments are Disposed of.

So, this is pretty simple stuff. It is just the conversion from Java to .NET and the other way around that can cause some troubles. So just keep in mind, that if your GREF count is rising, then you should probably look into Disposing of some of your stuff.

Again the final solution can be found on → GitHub

Matching UIKeyboard speed and curve to your animation

|

I have a ViewController in my Xamarin.iOS application, where i scale the View Frame when the keyboard shows. However, I had some trouble with matching the speed and curve of the animation to the keyboards animation. Though I found a pretty good solution, which takes the values from the keyboard itself, through the UIKeyboardWillShowNotification.

Disabling ActionBar menu items

|
I have some use cases where I want to temporarily disable ActionBar menu items, such that they are not clickable, but also so they are a different color from the active ones. The default SetEnabled method on IMenuItem does not do this for you. Sure it disables the item, however the visual state does not change. Hence, I found a nifty way to change this and made my own SetEnabled extension method.

Using this extension method can grey out menu items, so they appear disabled from a UX perspective. The method takes some more parameters, as it needs to get the resource id of the Drawable you want to use for the greyed out item and the current Context, such that it can get it from the application resources.

Getting Support V7 working with MvvmCross

|
Recently Xamarin added Support V7 AppCompat and GridView to their Component store, which you now can use instead of ActionBarSherlock or LegacyBar and it is Google's official way to support ActionBar's on API's which natively do not support it. However it does not work straight out of the box and you need to mimic what MvxActivity does in your own implementation. So here's the code I used to re-create MvxActivity to inherit from ActionBarActivity instead of Activity, which Support V7 needs.

This way you only need to replace MvxActivity with MvxActionBarActivity where needed and also add one of the AppCompat Themes to your Activity: Theme = "@style/Theme.AppCompat.Light"

Xamarin officially announced PCL support and more...

|
It has been a little while since last update from me. Since then a lot of stuff has happened in the Xamarin world. They have teamed up with Microsoft and released official PCL support, while Microsoft has loosened up their licenses on Bcl and their HttpClient among others. This is really great news!

I have already heard about people releasing their libraries for Xamarin because of the PCL support, among them is Jon Skeet, which is working with his team on Noda Time. There was some questions about what is actually supported in the various profiles, and I have spent the day today to track that down and test various PCL's. For now I have only tested for async/await and Tasks support and which profile supports which targets and contains which subsets.

This can be seen in the table below or by visiting my Google Spreadsheet I have made with it.



From what I can see the best choice for a profile to pick in your project seems to be either profile 78 or 158. The former is reported to not have Timer and ThreadPool in it and if you need support for Silverlight 5, profile 158 seems to be the best choice overall.