【问题标题】:Android ListView: Can not center items on start up, due to Null Pointer ExceptionAndroid ListView:由于空指针异常,无法在启动时居中项目
【发布时间】:2012-06-12 06:44:59
【问题描述】:

这是我第一次在这里发帖,我是一个愚蠢的新手,所以我希望那里的人能帮助我并原谅我的无知。

我有一个 ListView,其中填充了一个 ArrayAdapter。当我滚动或单击时,我希望将所选项目或最接近垂直中心的项目强制到屏幕的确切垂直中心。如果我调用 listView.setSelection(int position) 它会在屏幕顶部对齐所选位置,所以我需要使用 listView.setSelectionFromTop(position, offset) 代替。为了找到我的偏移量,我从 ListView 的一半高度中取了一半的 View 高度。

因此,我可以在 OnItemClick 或 OnScrollStateChanged 中轻松地将我的项目垂直居中,使用以下内容:

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

这一切都很好。我的问题是初始 ListView 设置。我希望在活动开始时将项目居中,但我不能,因为我从以下位置获得 NullPointerException:

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

我知道这是因为 ListView 尚未渲染,所以当我从 OnCreate() 或 OnResume() 调用它时它没有子视图。

所以我的问题很简单:如何强制我的 ListView 在启动时呈现,以便获得所需的高度值?或者,还有其他方法可以在 ListView 中垂直居中项目吗?

提前感谢您的帮助!

【问题讨论】:

标签: android android-listview


【解决方案1】:
int y = listView.getChildAt(0).getHeight();

我知道这是因为 ListView 尚未渲染,所以当我从 onCreate()onResume() 调用它时它没有子视图。

你应该打电话给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();




    }       
});

【讨论】:

  • 我确实看到 onScroll() 活动一开始就被调用,实际上它似乎被调用了几次。每次滚动列表时也会多次调用它。但是当我尝试与任何列表视图行进行通信时,我仍然会得到 Null,所以我认为它们仍然不存在。我正在使用 OnScrollStateChanged,因为我可以在完成滚动后设置 ListView 位置(int scrollstate = OnScrollListener.SCROLL_STATE_IDLE)。
【解决方案2】:

我在这里回答我自己的问题,但它非常有技巧。我认为这很有趣,因为它揭示了列表视图的行为。

问题在于尝试对尚不存在(尚未呈现)的数据(列表视图行)采取行动。 listview.getChildAt(int) 为 null,因为 listview 还没有子级。我发现在创建活动时立即调用 onScroll(),所以我只是将所有内容放在一个线程中并延迟 getChildAt() 调用。然后我将整个东西封装在一个布尔包装器中,以确保它只被调用一次(在启动时)。

有趣的是,我只需将调用延迟 1 毫秒即可让一切正常。而且速度太快了,肉眼看不见。

就像我说的,这完全是一个 hack,所以我确信这一切都是一个坏主意。感谢您的帮助!

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

【讨论】:

    【解决方案3】:

    我使用一种我认为稍微简单的解决方案也达到了同样的效果

    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);
       }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 2018-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多