Fun With Flags

Creating a country picker dialog with vector drawables

Barry Irvine
5 min readNov 28, 2016

My wife often jokes (I think so anyway) that I have the same emotional quotient as the fictional theoretical physicist, Sheldon Cooper, and that’s why I relate so well to the humour in Big Bang Theory. It is, therefore, with great trepidation that I begin to write a blog sharing the same name as his more (in)famous vlog.

Recently I got some feedback from Google on the Depop app that there was scroll clipping on our country picker dialog. Up till now we’ve been using this country picker library but I felt it was time to write my own. The original library was using a single png in the mipmap directory for each country flag (I was never sure why; but I think I have a better understanding now) and was also using older listviews instead of recycler views.

First of all I wanted to create a VectorDrawable flag of every country in the picker. I figured that this would save on the apk size. For the non-Android people out there, a VectorDrawable is a lightweight version of standard SVG files — but not all tags are handled. I found all the svgs on this github repo and then ran them through a batch tool to convert them to Android format. 2 years after the launch of the Lollipop version of Android that brought vectors to the platform, this is still a bit error-prone.

After some manual corrections to remove the most glaring errors (for example):

  • the simple Bolivian tricolor wouldn’t convert
  • the Palau flag was all over the place
  • the original flag for Niue was already wrong

After the batch conversions and a few manual tweaks, I finally had all my image files (although the vector paths weren’t the most efficient). I then created a relatively simple Country enum that mapped the ISO-3166 country codes to my drawables.

AD(R.drawable.ic_ad),
AE(R.drawable.ic_ae),
...
ZM(R.drawable.ic_zm),
ZW(R.drawable.ic_zw);
private final int mCountryFlag;

Country(@DrawableRes final int countryFlag) {
mCountryFlag = countryFlag;
}
public Drawable getFlagDrawable(final Context context) {
return AppCompatResources.getDrawable(context, mCountryFlag);
}

I could just have derived the drawable name from the enum name (or used a more lightweight static String constant and done likewise) but some countries (in particular French overseas territories) use a duplicate flag and it’s a waste of resources to have the same file contents multiple times.

Now that I have a list of countries and their associated flags I can create my adapter. Obviously we don’t want the list to be sorted by the ISO country code: an English-speaking user would not expect Switzerland (CH) to appear before Germany (DE); just as importantly we should pay attention to the accented characters: Åland Islands should appear after Afghanistan.

I therefore first create a list of countries and then sort it based on my current language and the collation rules for the locale:

private List<Country> mCountries = Arrays.asList(Country.values());...final Locale locale = context.getResources().getConfiguration().locale;
final Collator collator = Collator.getInstance(locale);
final String language = locale.getLanguage();
collator.setStrength(Collator.PRIMARY);
Collections.sort(mCountries, new Comparator<Country>() {
@Override
public int compare(final Country country1, final Country country2) {
return collator.compare(
country1.getCountryName(language), country2.getCountryName(language));
}
});

This uses a convenience method for getting the country’s display name for the current language within the Country enum class:

public String getCountryName(final String language) {
return new Locale(language, name()).getDisplayCountry();
}
The country picker

So now we have a sorted list of countries with their associated flags, I can hook up a recyclerview and a view holder to my adapter and, voila, I have a sorted list of countries with their flags. Happy days!

But wait a second. If I scroll quickly up and down the list I can see it is gets quite “sticky”. If I compare this to the original listview with pngs; it is buttery smooth. What’s going on?

Perhaps my list item is the problem, I have a horizontal linear layout with an imageview and a textview in it. After replacing that with a single textview (with a compound drawable at the start) it still lags.

Eventually I discover the root cause — setting the compound drawables (or drawable resource of an imageview) as a vector drawable resource has a hidden cost, compared to setting it to a png drawable resource. Now, as I mentioned earlier, the vector drawables don’t have the most efficient paths in them — perhaps if I had lots of a time and a designer to help we could redefine all the drawables so that they had no superfluous groups, clip paths and the minimal number of paths. Maybe if the viewport was closer to my desired size — 32 x 24dp instead of 640x480 pixels — then that would help.

I don’t really have the time to do that (I was, after all, just trying to correct a minor clipping problem in the country picker and I’ve now gone so far down the rabbit hole that the Mad Hatter is speaking with a distinctly Aussie twang). I could just drop the images and display the country names but…meh. It’s nice to have some extra visuals.

After some experimentation, I discover that it was just the conversion of the vector resource to a drawable that was costly — not the conversion of the drawable to a bitmap — so if I create a Map of countries to drawables and use that map to retrieve the drawable each time the view holder gets bound the problem was solved. Constructing the Map was quite expensive so I chuck that on a background thread when creating the adapter and retrieve the drawable (if available yet) from it when binding the view holder.

But is there another way that I can have flag images on my picker without using any type of drawables? Doesn’t Android have flag emoji everywhere (at least from Lollipop onwards)? An emoji is just a special string so I wouldn’t need to worry about images at all! Find out how I got on with flag emoji in Android and get the links to the sample code in the next exciting episode of Fun with Flags

As usual, if you enjoyed this post, I’d appreciate a recommend, follow, share or tweet.

--

--

Barry Irvine

Writing elegant Android code is my passion — but with 20+ years experience in roles from programme delivery to working at the coal face, I’ve seen it all.