I have a GridView with 4 images per row, and normally has more than the slightly fewer than 5 rows that will fit on the screen at one time.
Originally, it would reset back to the top every time I regenerated its content. So, I took a tip from a post someone made regarding ListAdapter, and came up with the following:
Before I regenerate the GridView, I note the value of getFirstVisiblePosition() for the current one.
After regenerating it, I call setSelection() with the value I got earlier from getFirstVisiblePosition().
The problem is, every time I regenerate the GridView, it rolls backwards by one row until it reaches the top. It looks like for whatever reason, it returns 0 if EITHER the first OR second row is the first row visible, then returns n-4 (there are 4 items per row) thereafter.
Example:
row 1 is the first visible row: returns 0
row 2 is the first visible row: returns 0
row 3 is the first visible row: returns 4
row 4 is the first visible row: returns 8
As a secondary problem, the first call to setSelection() makes it snap if the user didn't leave it in exactly the right position. Is there any way to just ask Android, "How many pixels down has the current GridView been scrolled by the user", and later tell it, "pre-scroll this newly-rendered GridView downward by N pixels" so that the content of the elements might change, but the grid itself will appear stable and remain in the same position it was left in by the user before th开发者_StackOverflow中文版e update?
Example code:
// (uList = List<User>;)
// see what the current gridview's top position is
// returns 0 for rows zero and one,
// returns n-4 for rows two and beyond (n = row x 4)
int idx = gridview.getFirstVisiblePosition();
gridview.setAdapter(new ImageAdapter(TabViewActivity.this, uList));
// ImageAdapter is subclass of BaseAdapter
// if it matters, it's populating View with slightly-hacked Droid-Fu
// WebImageView objects (the official version doesn't support overlaying
// bitmaps, and has its own LayoutParams hardcoded).
// restore the previous incarnation's top position
// the "+4" is a nasty hack to make it sort of work for all rows but the first
gridview.setSelection(idx+4);
public class ImageAdapter extends BaseAdapter {
// ...
public View getView(int position, View v, ViewGroup parent) {
User u = userList.get(position);
LayoutParams lp = new LayoutParams(70,70);
lp.gravity = Gravity.CENTER;
IBitmapFilter filter = new UserBitmapFilter(u, overlays);
StyledWebImageView w = new StyledWebImageView(context, u.getIconUrl(app), true, lp, filter);
w.setTag(u);
return w;
}
}
Update: The accepted answer doesn't quite tell the whole story, but helped me to fix the problem anyway.
In the end, I fixed the problem by reusing the ImageAdapter object instead of generating a new one every time the underlying content changed. It fixed the problem. All the above code was basically replace by:
if (gridviewImageAdapter.update(uList))
gridviewImageAdapter.notifyDataSetChanged();
and adding a method to the ImageAdapter class:
public boolean update(List<User> uList) {
// make backup copy of the old list
// replace the values
// compare old and new lists, return true if different.
}
You should only need to call notifyDataSetChanged()
on the Adapter
to reflect changes in the data driving your list.
How are you regenerating the view?
It sounds like you're working against the framework instead of working with it. Watch this video, it helps explain a lot about ListView
and updating views from Adapter
s. I found it really helpful.
精彩评论