I am trying to make the background of a ListView scroll with the ListView. I am basing my approach on this class in Shelves, but while in Shelves everything has the same height, I can't make the same guarantee.
I have an activity like so:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.listView);
List<String> items = new ArrayList<String>();
for(int i=0; i < 100; ++i) {
items.add("Hello " + i);
}
CustomArrayAdapter adapter = new CustomArrayAdapter(this, items);
listView.setAdapter(adapter);
}
}
Where CustomArrayAdapter is:
public class CustomArrayAdapter extends ArrayAdapter<String> {
private List<Integer> mHeights;
public View getView(int position, View convertView, ViewGroup parent) {
//snip
}
}
What I want to do is populate mHeights in the adapter with heights of the rows of the view.
My main attempt was to do this, in getView():
if(row.getMeasuredHeight() == 0) {
row.measure(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
}
mHeights.set(position, row.getMeasuredHeight());
I've tried several ways to do this, but I can't get anything to work.
In getView
, if I call getHeight()
I get a return value of 0, while if I call getMeasuredHeight()
, I get something non-zero but not the real height. If I scroll down and then up again (taking one of the rows out of view) getHeight() == getMeasuredHeight()
and both have the correct value. If I just update mHeights in getView as I go (by saying mHeights.set(position, row.getHeight()
); it works - but only after I've scrolled to the bottom of the ListView. I've tried calling row.measure() within the getView method, but this still causes getHeight()
to be 0 the first time it is run.
My question is this: how do I calculate and populate mHeights with the correct heights of the rows of the ListView? I've seen some similar questions, but they don't appear to be what I'm looking for. The ViewTreeObserver
method seems promising, but I can't figure out how to force calls to getView() from it (alternately, to iterate the rows of the ListView). Calling adapter.notifyDataSetChanged()
causes an infinite (although non-blocking) loop.
This is related to my previous question on the subject, which seems to have missed the point: ListView distance from top of the list