I need to paint an overlay image onto a SeekBar in my ListView rows. This isn’t too hard to do and the code in this question accomplishes that by painting the row number in a bitmap and placing it as the progress drawable.
The problem that I am having is that this only works one time. When the view is recycled to be used for another row, the drawable disappears.

The first 10 views (positions 0 through 9) worked. Everything after that fails. There is no error or exception. Android just stops drawing that layer. If I scroll down and then back up, none of them work (as they have all been recycled).
How do I get Android to always draw this overlayed image? I imagine there is some sort of caching or invalidation that I need to perform, but I just don’t know what it is yet.
public class ViewTest extends ListActivity {
// replace the progress drawable with my custom drawable
public void setSeekBarOverlay(SeekBar seekBar, String overlayText) {
Bitmap bitmap = Bitmap.createBitmap(100, 12, Bitmap.Config.ARGB_4444);
new Canvas(bitmap).drawText(overlayText, 10, 12, new Paint());
Drawable d = new BitmapDrawable(bitmap);
((LayerDrawable) seekBar.getProgressDrawable()).setDrawableByLayerId(android.R.id.progress, d);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setListAdapter(new ListAdapter() {
// return the view. Recycle them if possible.
public View getView(int pos, View v, ViewGroup vg) {
if (v == null) {
v = View.inflate(ViewTest.this, R.layout.seekbar, null);
}
String s = String.valueOf(pos);
((TextView) v.findViewById(android.R.id.text1)).setText(s);
setSeekBarOverlay((SeekBar) v.findViewById(R.id.seekbar), s);
return v;
}
... cut ...
});
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
seekbar.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight">
<TextView
android:id="@android:id/text1"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="wrap_content" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
</LinearLayout>
This is a tough one that I don’t think will get much traffic, so I’m going to answer it myself since I found the solution.
Another SO question/answer, Android ProgressBar.setProgressDrawable only works once?, got me halfway there but the solution didn’t work for me. In the other question, the code was trying to replace the entire progressDrawable (
setProgressDrawable()). I’m not doing that here as I’m just updating a layer in the existing progressDrawable. After some playing around, with similar approaches, I found something that worked. You have to get the bounds of the drawable that is being updated (in this case, one of the layers) and set the bounds later.Seems like a bug in the platform, but this workaround seems to make it work. Hope this helps someone else someday.