Styled Formats

Where styled text gets tricky is with styled string formats, as String.format() works on String objects, not Spanned objects with formatting instructions. If you really want to have styled string formats, here is the workaround:

1. Entity-escape the angle brackets in the string resource (e.g., this is <b>%1$s</b>).

2. Retrieve the string resource as normal, though it will not be styled at this point (e.g., getString(R.string.funky format)).

3. Generate the format results, being sure to escape any string values you substitute in, in case they contain angle brackets or ampersands.

String.format(getString(R.string.funky format), TextUtils.htmlEncode(strName));

4. Convert the entity-escaped HTML into a Spanned object via Html.fromHtml().

someTextView.setText(Html

.fromHtml(resultFromStringFormat));

To see this in action, let's look at the Resources/Strings demo, which can be found in the Source Code area of http://apress.com. Here is the layout file:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout width="fill parent" android:layout height="fill parent"

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout width="fill parent"

android:layout height="wrap content" >

<Button android:id="@+id/format" android:layout width="wrap content" android:layout height="wrap content" android:text="@string/btn name" />

<EditText android:id="@+id/name" android:layout width="fill parent" android:layout height="wrap content" />

</LinearLayout>

<TextView android:id="@+id/result" android:layout width="fill parent" android:layout height="wrap content" />

</LinearLayout>

As you can see, it is just a button, a field, and a label. The intent is for somebody to enter their name in the field, then click the button to cause the label to be updated with a formatted message containing their name.

The Button in the layout file references a string resource (@string/btn name), so we need a string resource file (res/values/strings.xml):

<?xml version="1.0" encoding="utf-8"?> <resources>

<string name="app name">StringsDemo</string> <string name="btn name">Name:</string>

<string name="funky format">My name is &lt;b&gt;%1$s&lt;/b&gt;</string> </resources>

The app name resource is automatically created by the activityCreator script. The btn name string is the caption of the Button, while our styled string format is in funky format. Finally, to hook all this together, we need a pinch of Java:

package com.commonsware.android.resources;

import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.text.Html; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView;

public class StringsDemo extends Activity { EditText name; TextView result;

@Override public void onCreate(Bundle icicle) { super. onCreate(icicle); setContentView(R.layout.main);

name=(EditText)findViewById(R.id.name); result=(TextView)findViewById(R.id.result);

Button btn=(Button)findViewById(R.id.format);

btn.setOnClickListener(new Button.OnClickListener() {

public void onClick(View v) { applyFormat();

private void applyFormat() { String format=getString(R.string.funky format); String simpleResult=String.format(format,

TextUtils.htmlEncode(name.getText().toString())); result.setText(Html.fromHtml(simpleResult));

The string resource manipulation can be found in applyFormat(), which is called when the button is clicked. First, we get our format via getString()—something we could have done at onCreate() time for efficiency. Next, we format the value in the field using this format, getting a String back, since the string resource is in entity-encoded HTML. Note the use of TextUtils. htmlEncode() to entity-encode the entered name, in case somebody decides to use an ampersand or something. Finally, we convert the simple HTML into a styled text object via Html.fromHtml() and update our label.

When the activity is first launched, we have an empty label (see Figure 19-1).

ftRffle 1:03 PM I

ftRffle 1:03 PM I

Figure 19-1. The StringsDemo sample application, as initially launched

However, if we fill in a name and click the button, we get the result seen in Figure 19-2.

Figure 19-2. The same application, after filling in some heroic figure's name
0 0

Post a comment