String model
to use a RowModel
.
• The ArrayAdapter
subclass (CheckAdapter
) in getView()
looks to see if convertView
is null. If so, we create a new row by inflating a simple layout (see the following code) and also attach a ViewWrapper
(also in the following code). For the row’s RatingBar
, we add an anonymous onRatingChanged()
listener that looks at the row’s tag (getTag()
) and converts that into an Integer
, representing the position within the ArrayAdapter
that this row is displaying. Using that, the checkbox can get the actual RowModel
for the row and update the model based upon the new state of the rating bar. It also updates the text adjacent to the RatingBar
when checked to match the rating-bar state.
• We always make sure that the RatingBar
has the proper contents and has a tag (via setTag()
) pointing to the position in the adapter the row is displaying.
The row layout is very simple: just a RatingBar
and a TextView
inside a LinearLayout
:
<?xml version='1.0' encoding='utf-8'?>
<LinearLayout xmlns:android='http://schemas.android.com/apk/res/android'
android:layout_width='fill_parent'
android:layout_height='wrap_content'
android:orientation='horizontal'
>
<RatingBar
android:id='@+id/rate'
android:layout_width='wrap_content'
android:layout_height='wrap_content'
android:numStars='3'
android:stepSize='1'
android:rating='2' />
<TextView
android:id='@+id/label'
android:paddingLeft='2px'
android:paddingRight='2px'
android:paddingTop='2px'
android:textSize='40sp'
android:layout_width='fill_parent'
android:layout_height='wrap_content'/>
</LinearLayout>
The ViewWrapper
is similarly simple, just extracting the RatingBar
and the TextView
out of the row View
:
class ViewWrapper {
View base;
RatingBar rate = null;
TextView label = null;
ViewWrapper (View base) {
this.base = base;
}
RatingBar getRatingBar() {
if (rate==null) {
rate = (RatingBar)base.findViewById(R.id.rate);
}
return(rate);
}
TextView getLabel() {
if (label==null) {
label = (TextView)base.findViewById(R.id.label);
}
return(label);
}
}
And the result (Figure 9-3) is what you would expect, visually.

Figure 9-3.
This includes the toggled checkboxes turning their words into all caps (Figure 9-4).

Figure 9-4.
…And Checking It Twice
The rating list in the previous section works, but implementing it is very tedious. Worse, much of that tedium would not be reusable except in very limited circumstances. We can do better.
What we’d really like is to be able to create a layout like this:
<?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' >
<TextView
android:id='@+id/selection'
android:layout_width='fill_parent'
android:layout_height='wrap_content'/>
<com.commonsware.android.fancylists.seven.RateListView
android:id='@android:id/list'
android:layout_width='fill_parent'
android:layout_height='fill_parent'
android:drawSelectorOnTop='false'
/>
</LinearLayout>
where, in our code, almost all of the logic that might have referred to a ListView
before “just works” with the RateListView
we put in the layout:
public class RateListViewDemo extends ListActivity {