-2

我遇到的问题是它listView.getLastVisiblePosition总是返回 -1 所以我不能隐藏searchView. 我在设置后立即检查它,adapter并且在我尝试放置它的任何地方它仍然返回-1。我没有在文档中看到为什么会这样,但我想如果ListView没有显示任何项目,它会返回 -1。但是,listView.getFirstVisiblePosition()即使显示多个项目,也始终返回 0。

我在这里尝试了这两种方法,但是在获取错误值时并没有什么不同。

@SuppressLint("NewApi") private void setFilters(String curType, Object curFilter)
{
    // initialize several lists
    itemsAdapter = new ArrayAdapter<Rowdata>(this, R.layout.list_item_text, foodItems);
    listView.setAdapter(itemsAdapter);

    int numItems = listView.getLastVisiblePosition() - listView.getFirstVisiblePosition();
    if (numItems > foodItems.length)    
    {   searchField.setVisibility(View.GONE);   }
    else
    {   searchField.setVisibility(View.VISIBLE);    }
}

Button每当按下 a 或更改可以过滤列表的文本时,都会调用此方法。所以问题是为什么listView.getLastVisiblePosition()总是返回-1,为什么listView.getFirstVisiblePosition()总是返回0?没有错误/异常,除了没有得到预期的结果外,一切都运行良好。注意:itemsAdapter.getCount()返回正确的值。

还有,我必须支持API >=10

编辑

如果有人需要澄清,请告诉我。但基本上,我有一个EditText我用来搜索列表的。当列表中的项目不超过屏幕上的项目时,我想隐藏它。listView.getLastVisiblePosition()总是返回 -1

我真的很想知道原始问题的原因,但是如果有人有更好的方法在项目都适合屏幕时隐藏搜索框,我愿意接受建议。

更新

我放了一个断点,在那里我得到了,和onItemClick()的正确值。在此之前,我分别得到 0、-1 和。getFirstVisiblePosition()getLastVisiblePosition()listView.getChildCount()null

4

4 回答 4

3

你需要做的是大致

listview.post(new Runnable() {
    public void run() {
        listview.getLastVisiblePosition();
    }
});

为什么这样而不是直接?

Android 应用程序在称为 UI / 主线程的大事件循环中运行。在那里执行的一切都是某个事件的结果。例如,当您Activity需要创建某种活动创建事件时。循环将执行处理此事件的代码,例如,一旦您被认为是“创建”,就会调用该onCreate方法。它可能会在同一迭代中调用多个方法,但这并不重要。

当您在任何这些方法中设置诸如 UI 之类的onSomething东西时,实际上并没有直接绘制任何内容。您所做的只是设置一些状态变量,例如 new Adapter. 一旦您从这些on方法返回,系统就会重新获得控制权,并将检查下一步需要做什么。

例如,系统将检查窗口是否需要重绘,如果需要,则将重绘事件排入事件队列中,该事件稍后由循环执行。如果不需要绘制任何内容,则它只是空闲并且将等待例如也为该循环排队的触摸事件。

回到你的问题:通过调用.setAdapter()你基本上重置了ListView. 而且由于ListView只有您将控制权交还给系统后才会进行实际更新,因此您将无法从中获得任何有用的信息.getLastVisiblePosition()

之前需要做的ListView是指示重新绘制或测量它的新尺寸,计算它拥有的项目数量等等。一旦完成,它将能够为您提供所需的信息。

.post(Runnable r)只需将 Runnable 排入事件队列,一旦它在队列中排在第一位,就会由循环执行。

aRunnable不需要 a Thread,它只是一个带有名为的方法的常规 Object ,并且 arun()的合同Runnable只是某些东西(通常恰好是 a Thread)可以调用该run()方法来执行您想要运行的任何内容。神奇的循环就是这样做的。

您发布可运行文件的结果看起来有点像这样的 inn 伪代码:

void loop() {
    yourActivity.onSomething() { loop.enqueue(runnable) }
    ListView.redraw()            //       |
    runnable.run()               //    <--+
}
于 2013-08-02T14:15:05.830 回答
0

您可以在此处参考我的回答Strange problem with broadcast receiver in Android不完全相同,但您可以了解您的代码为何无法正常工作。

为了更清楚,当您将适配器设置为 ListView 时,尚未绘制任何内容,并且 getLastVisiblePosition() 方法只能在 listview 完成绘制所有可见子项并知道哪个是最后一个可见子项后返回正确的值一。

所以,我可以在这里建议的最合适的方法是在 listView 完成绘制后触发回调,然后我们得到正确的值。

绘制后带有监听器的 ListView:

static class MyListView extends ListView {
        private OnDrawCompletedListener mOnDrawCompletedListener;

        public MyListView(Context context) {
            super(context);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (mOnDrawCompletedListener != null) {
                mOnDrawCompletedListener.onDrawCompleted();
            }
        }

        public void setOnDrawCompletedListener(OnDrawCompletedListener listener) {
            mOnDrawCompletedListener = listener;
        }

        public static interface OnDrawCompletedListener {
            public void onDrawCompleted();
        }
    }

获取最后可见位置的示例代码

mListView.setAdapter(new EfficientAdapter(this));
//Will get -1 here
Log.e("Question-17953268",
        "getLastVisiblePosition  = "
                + mListView.getLastVisiblePosition());

mListView.setOnDrawCompletedListener(new OnDrawCompletedListener() {

    @Override
    public void onDrawCompleted() {
        //Will get correct value here
        Log.e("Question-17953268",
                "getLastVisiblePosition  = "
                        + mListView.getLastVisiblePosition());
    }

});
于 2013-08-07T12:30:03.783 回答
0

感谢zapl的回答,我能够得到我需要的东西。我想我会发布完整的代码以防它帮助任何人

listView.post(new Runnable()
{       
    public void run()
    {
        int numItemsVisible = listView.getLastVisiblePosition() - 
                listView.getFirstVisiblePosition();
        if (itemsAdapter.getCount() - 1 > numItemsVisible)
        {   searchField.setVisibility(View.VISIBLE);    }                                   
        else
        {   
            searchField.setVisibility(View.GONE);   
            setFilters("searchtext", "");
        }               
    }
});
于 2013-08-08T19:22:15.703 回答
0

我解决这个问题的建议不会是专业的或轻量级的。

我建议您应该计算 listView 中的所有视图并检查它们中的每一个是否可见。

例子:

   private int getIndexOfLastVisibleView(ListView view){

      int count = view.getChildCount()-1;

      for(int i = count ; i>=0 ; i--){
         View checkedView = view.getChildAt(i);
         if(checkedView.isShown()){
            return i;
         }
      }


      return -1;
  }

可能并不完美,但我希望它能奏效。

于 2013-07-30T17:28:57.370 回答