Android ListView: Unable to center items at startup due to Null Pointer exception

This is my first post here, and I'm a stupid newbie, so I hope someone out there can help me and excuse my ignorance.

I have a ListView that is populated with an ArrayAdapter. When I either scroll or click, I want the selected item or the item closest to the vertical center to be forced to the 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 the height of the view from half the height of the ListView.

So, I can vertically center my element quite easily, 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 of this works great. My problem is with the initial setup of ListView. I want the element to be centered when the action starts, but I cannot, because I get a NullPointerException:

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

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

So my question is simple: how can I get my ListView to display at startup so that I can get the right height value? Or, alternatively, is there another way to center elements vertically inside a ListView?

Thanks in advance for your help!

+4
source share
3 answers

I answer my question here, but this is a very hack. I think this is interesting because it sheds light on the behavior of lists.

The problem was trying to manipulate data (list line) that did not exist (it was not shown). listview.getChildAt (int) was null because there were no children in listview yet. I found out that onScroll () is called immediately when the action is created, so I just put everything on the stream and delay the call to getChildAt (). Then I put all this into a Boolean shell to make sure that it is ever called only once (at startup).

Interestingly, I only had to postpone the call for 1 ms, so that everything was in order. And it's too fast for the eyes to see.

As I said, it’s all a hack, so I’m sure that 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 
0
source
 int y = listView.getChildAt(0).getHeight(); 

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

You should call it 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(); } }); 
+1
source

I achieved the same, using, in my opinion, a 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); } }); 
0
source

All Articles