【问题标题】:Hide custom search bar if all items in adapter are showing如果适配器中的所有项目都显示,则隐藏自定义搜索栏
【发布时间】:2013-07-30 17:13:50
【问题描述】:

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

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

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

还有,我要支持API &gt;=10

编辑

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

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

更新

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

【问题讨论】:

  • 我真的不知道我是否完全理解这个问题。您有一个列表视图,其中包含可以通过 getCount() 获得的项目计数。在这个 listView 里面你有一个你想要得到的 searchView 是吗? searchView 是否有任何 id 分配给它?
  • @MateuszZając 我希望listView.getLastVisiblePosition() 返回View 中最后一个View 中的索引ListView 所以如果它小于或等于我不使用的列表大小'不显示搜索栏。我希望这能解决一些问题。
  • 绘制之前不知道。尝试通过listView.post() 发布一个可运行文件,看看你是否在那里得到了正确的值。
  • 只是一个reference
  • @zapl 谢谢,做到了。现在,如果有人可以向我解释为什么这有效,我可以发出赏金。也许我不像我想的那样理解Runnable。但我不明白为什么它知道这里的计数但不是没有Runnable。如果它在这里绘制,那么不应该在没有 `Runnable 的情况下绘制它吗?

标签: android android-listview android-search


【解决方案1】:

你需要做的是粗略的

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

为什么是这样而不是直接?

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

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

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

回到您的问题:通过调用.setAdapter(),您实际上重置了ListView 的所有状态。而且由于ListView 的实际更新只会发生在您将控制权交还给系统之后,您将无法从.getLastVisiblePosition() 中获得任何有用的信息。

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

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

Runnable 不需要Thread,它只是一个带有名为run() 的方法的常规对象,而Runnable 的合同就是这样的东西(通常恰好是Thread)可以调用run() 方法来执行你想运行的任何东西。魔法循环就是这样做的。

你发布一个可运行的结果是看起来像这样的伪代码:

void loop() {
    yourActivity.onSomething() { loop.enqueue(runnable) }
    ListView.redraw()            //       |
    runnable.run()               //    <--+
}

【讨论】:

    【解决方案2】:

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

    我建议您应该计算 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;
      }
    

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

    【讨论】:

    • 感谢您的回复。如果可以的话,我想要一些更整洁的东西,但如果我不明白,我可以试试这个。另外,我真的很想知道为什么getLastVisiblePostition() 每次都返回 -1,因为这是问题的核心
    • 很抱歉,在这里我无法为您提供帮助。我从来没有以任何方式使用过这种方法。
    • 无论如何,我很感激这个答案。如果我很快找不到我想要的东西,我会尝试并让你知道。谢谢!
    • 我现在至少准备投票,但这也行不通。如果你看到我的更新,你就会明白为什么。
    【解决方案3】:

    您可以在此处参考我的答案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());
        }
    
    });
    

    【讨论】:

      【解决方案4】:

      感谢 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", "");
              }               
          }
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-03
        • 1970-01-01
        • 2016-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多