4

This is my first ever post here and I'm a dumb novice, so I hope someone out there can both help me and excuse my ignorance.

I have a ListView which is populated with an ArrayAdapter. When I either scroll or click, I want the selected item, or the item nearest the vertical center, to be forced to the exact vertical center of the screen. If I call listView.setSelection(int position) it aligns the selected position at the top of the screen, so I need to use listView.setSelectionFromTop(position, offset) instead. To find my offset, I take half of the View's height from the half of the ListView's height.

So, I can vertically center my item easy enough, within OnItemClick or OnScrollStateChanged, with the following:

        int x = listView.getHeight();
        int y = listView.getChildAt(0).getHeight();                 
        listView.setSelectionFromTop(myPosition, x/2 - y/2);

All this works fine. My problem is with the initial ListView setup. I want an item to be centered when the activity starts, but I can't because I get a NullPointerException from:

int y = listView.getChildAt(0).getHeight();

I understand this is because the ListView has not yet rendered, so it has no children, when I call this from OnCreate() or OnResume().

So my question is simply: how can I force my ListView to render at startup so I can get the height value I need? Or, alternatively, is there any other way to center items vertically within a ListView?

Thanks in advance for any help!

4

3 回答 3

1
int y = listView.getChildAt(0).getHeight();

I understand this is because the ListView has not yet rendered, so it has no children, when I call this from onCreate() or onResume().

You should call it in onScroll.

listView.setOnScrollListener(new OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
         //Write your logic here

         int y = listView.getChildAt(0).getHeight();




    }       
});
于 2012-06-12T06:59:13.590 回答
0

I'm answering my own question here, but it's very much a hack. I think it's interesting because it sheds some light on the behavior of listviews.

The problem was in trying to act on data (a listview row) that did not yet exist (it had not been rendered). listview.getChildAt(int) was null because the listview had no children yet. I found out onScroll() is called immediately when the activity is created, so I simply put everything in a thread and delayed the getChildAt() call. I then enclosed the whole thing in a boolean wrapper to make sure it is only ever called once (on startup).

The interesting thing was that I only had to delay the call by 1ms for everything to be OK. And that's too fast for the eye to see.

Like I said, this is all a hack so I'm sure all this is a bad idea. Thanks for any help!

private boolean listViewReady = false;

public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {

    if (!listViewReady){
        Thread timer = new Thread() {
            public void run() {
                try{
                    sleep(1);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{                   
                    runOnUiThread(new Runnable() {
                         public void run() {
                             myPosition = 2;
                             int x = listView.getHeight();
                             int y = listView.getChildAt(0).getHeight();                 
                             listView.setSelectionFromTop(myPosition, x/2 - y/2);
                             listViewReady = true;
                        }
                    });                     
                }
            }
        };
        timer.start();
    }//if !ListViewReady
于 2012-06-12T08:06:29.073 回答
0

I have achieved the same using a in my opinion slighlty simpler solution

mListView.post(new Runnable() {
   @Override
   public void run() {
      int height = mListView.getHeight();
      int itemHeight = mListView.getChildAt(0).getHeight();
      if (positionOfMyItem == myCollection.size() - 1) {
        // last element - > don't subtract item height
        itemHeight = 0;
    }
    mListView.setSelectionFromTop(position, height / 2 - itemHeight / 2);
   }
});
于 2013-02-13T14:09:14.257 回答