我遇到的问题是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 >=10
修改
如果有人需要澄清,请告诉我。但基本上,我有一个EditText
我用来搜索列表。当列表中的项目多于屏幕上的项目时,我想隐藏此项。 listView.getLastVisiblePosition()
始终返回-1
我真的很想知道原始问题的原因,但如果有人在屏幕上显示所有项目时有更好的隐藏搜索框的方式,我愿意接受建议。
更新
我在onItemClick()
放了一个断点,在那里我得到getFirstVisiblePosition()
,getLastVisiblePosition()
和listView.getChildCount()
的正确值。在此之前,我分别得到0,-1和null
。
答案 0 :(得分:3)
你需要做的是粗略
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()
方法来执行您想要运行的任何内容。神奇的循环就是这样。
发布runnable的结果看起来像伪代码,有点像这样:
void loop() {
yourActivity.onSomething() { loop.enqueue(runnable) }
ListView.redraw() // |
runnable.run() // <--+
}
答案 1 :(得分: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;
}
可能不完美,但我希望它会奏效。
答案 2 :(得分: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());
}
});
答案 3 :(得分: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", "");
}
}
});