18 February 2011

Using a custom font in WebView

In one of my projects, I needed to display some special characters that the Android OS by itself cannot seem to render. I figured that I would need to provide a custom font that includes the characters that I needed.

If I was using a TextView, I could use TextView#setTypeFace. But I was using a WebView and I feared that things would be more complicated than that. So how do I do this?

Here's how we can make it work.

Step 1: We would need to have our font face included in our project's /assets folder. So look for a TTF file that you can use freely, make sure the author/creator allows you to re-distribute it!

Step 2: Edit your HTML file to include some CSS stuff, just so the WebView would know what font you want to use. Here's a sample file:
<html><head><link href="YourCssFile.css" rel="stylesheet" type="text/css" /></head><body><span class="phon">This string contains special characters: əˈpåstrəfi </span></body></html>
Make sure that the href references are correct. In this case, my CSS file, HTML file and font file are in the same folder.

Step 3: Define your CSS file. In this case, our YourCssFile.css would be:
@font-face {
font-family: "My font";
src: url('MyFontFile.TTF');
}

.phon, .unicode {
display: inline;
font-family: 'My font', Verdana, sans-serif;
font-size: 14pt;
font-weight: 500;
font-style:normal;
color: black;
}
Step 4: Load the file in your WebView! You can use
WebView webView = (WebView) findViewById(R.id.myWebview);
webView.loadUrl("path/to/html/file");
or
webView.loadDataWithBaseURL("file:///android_asset/",
article, "text/html", Encoding.UTF_8.toString(), null);
If you will use the second option, your article variable would contain the HTML string. Just make sure that you escape your quotation marks with a backslash (\).
IMPORTANT NOTE: This feature seems to be broken in Android 2.0 and 2.1, as reported here.

17 February 2011

It never ends!

Been ultra super busy the past few weeks. Also learning a lot of new things. And renewing my battle with orientation change, AsyncTasks and dialog boxes.

So, I have been thinking of what to document here next. Here are my choices:
- Loading HTML pages stored in the SD card in a WebView
- Managing your SharedPreferences
- Using a ViewStub

I had a long list in my mind yesterday, but I managed to not write it down. *facepalm*

07 February 2011

*stealth ninja mode on*

Over the past couple of weeks, this blog has been getting unusually high traffic. Which means I get more than one hit per week.

So if it isn't too much to ask, can I please know how you got here, and what you were looking for. And please please let me know if I said anything wrong, or if you know of a better/easier/more optimized way to do the stuff I'm trying to talk about. Thanks! :)

02 February 2011

That damn seekbar thumb

If you have ever needed to use a SeekBar, you definitely would have noticed how hard it is to move the slider (aka thumb) when it is set to the minimum or maximum value. The slider tends to be cut in half, and fitting your finger into it to press it becomes a test of patience.

See how small the slider becomes when it reaches the far ends of the SeekBar? Crazy!

Luckily, I found a way (just today!) to move the slider just a little tiny bit to make it easier to press. Apparently, there is a method called setThumbOffset() that allows us to nudge the slider by a number of pixels.

It's pretty easy to use, aside from the fact that it accepts pixels and not dip measurements. Anyway, here's how to do it:
int pixels = convertDipToPixels(8f);
SeekBar mySeekBar = (SeekBar) findViewById(R.id.quiz_settings_seekbar);
mySeekBar.setOnSeekBarChangeListener(mySeekBarListener);
mySeekBar.setThumbOffset(pixels);
I convert dip measurements to pixels to better manage the growing number of resolutions of screen sizes present. Here's the code to do that:
private int convertDipToPixels(float dip) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float density = metrics.density;
return (int)(dip * density);
}
Aaaaaaaand this is now how our slider looks:Applause! Confetti! Applause!

30 January 2011

Enabling/disabling menu items on the fly

In one of my applications, I want to disable some menu entries if the database is not valid or is not present at all. To do that, I make use of the onPrepareOptionsMenu() API.

Let's say the user is on the Quiz activity. When the user presses the MENU button, the Quiz item should not be there anymore; and until the application validates the presence of a database, I want the Books item to be unclickable.

So I inflate my menu as usual from the XML file:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.my_menu, menu);

removeSomeItems(menu);
return true;
}

private void removeSomeItems(Menu menu){
MenuItem books = menu.findItem(R.id.menu_books);
books.setEnabled(false); // I want this item to be available eventually

menu.removeItem(R.id.menu_quiz); // I want this item to be unavailable for this activity
}

You have to remember though, that this method is called only ONCE, the very first time the user opens the menu.

The activity does its business as usual. When I am done checking if the database is there already, I want the user to be able to use the Books item. I have a boolean field that I set when the database is validated, and so now I can enable the menu.
@Override
public boolean onPrepareOptionsMenu (Menu menu){
super.onPrepareOptionsMenu(menu);

if(mIsDbValid){
MenuItem books = menu.findItem(R.id.menu_books);
books.setEnabled(true);
}

return true;
}


You can change the contents of the menu as often as you want using onPrepareOptionsMenu() because that method is called each and every time the user presses the MENU button.

And that's it!

18 January 2011

Just wondering

You know those postscripts that Google engineers have on their posts in forums? I wonder if they have a sort of "standards body" that came up with it. They all sound like this:
Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public
forums, where I and others can see and answer them


I wonder why I wonder about these things.

10 December 2010

Quick tip: Quick Formatting of Android XML Files

One of the most useful tools in Android's Eclipse plug-in is the Layout Editor. It is easy to experiment with layouts using the drag-and-drop enabled editor without having to worry about the correct syntax or if you are using the correct attribute name.

After creating your layout this way, however, you can end up with a messy XML file. I say "messy" in the sense that elements can run on in one veeeeeeeeeeeery long line, and if you are about to edit the XML file manually, this can be a nightmare.

I used to format the XML file by hand, putting in line breaks and correcting indentation. But one edit using the graphical layout editor and it's messed up again. And then I had a light bulb moment. Eclipse allows auto-formatting of code, but what about XML files? AHA!

It turns out that auto-formatting works for XML files too! Simply select all the contents of the XML file (CTRL-A) and then press the ultra magical shortcut CTRL-I and your XML file is clean and orderly as can be! YAY!

What happened to my layout editor?

There you are, happily creating your layout files in the Eclipse plug-in's layout editor. Dragging and dropping is a breeze. But then one day, you open a layout XML file and boom! No UI! All you see is the XML tree with all the nodes and attributes. What happened?

This happened to me and I was in a panic for a few seconds. Why do things like these have to happen to me? I tried opening a layout file from another project in the same workspace, and it has the UI! What happened?

It probably has something to do with the interpreter you used to open the XML file, a voice in my head said. So I tried right-clicking on the XML file, and lo and behold, I found it. I may have accidentally clicked on some file in one of my mad-clicking moments and changed the setting.

So anyway, to bring back the Layout UI Editor, right click on an XML file > Choose Open With > Android Layout Editor.

I would say that everything is handy dandy, but apparently, the engineers at Google decided that we developers need a little less help and removed the very useful up and down arrow keys in the Outline View when editing XML layouts. Why do they hurt us like this?

I WANT MY UP/DOWN KEYS BACK!

11 November 2010

What grammar?

My OC side was alarmed when suddenly, my Problems view in Eclipse was filled with warnings on my XML files. Each of my XML files had a warning with it, and that little yellow exclamation mark on the side:
No grammar constraints (DTD or XML schema) detected for the document

So how do you get rid of it? Go to Window > Preferences > XML > XML Files > Validation then set Indicate when no grammar is specified to Ignore. Click on Apply.

Clean up your project (Project > Clean).

If the problem doesn't go away, you may need to re-validate the XML files. Right click on the file then choose Validate from the popup menu. You can also right click on the folder (such as your res folder) and validate from there.

10 November 2010

TextView and MaxLines

I have a TextView (who doesn't?) and I want to adjust its height automatically, depending on the length of the text it will contain. Should be easy. It was, but it took me a couple of minutes to figure it out.

So I want my TextView to be by default one line tall, but be able to expand up to two lines. My initial set up was to set lines=1 and maxLines=2, but it was making the TextView always two lines. Not what I wanted! I went through the documentation again, read each word carefully, and then:
<TextView android:id="@+id/title"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:ellipsize="end"
android:maxLines="2"
android:minLines="1"
android:text="This is the text" />
So it turned out that you have to set both minLines and maxLines. TADA!