发现Android编程中的一个问题:如果在一个ListView上面放置一个可以接收焦点的东西,比如Button,当使用向上方向键滚动ListView到第一条后,焦点会移到上面的Button上,这个没问题。但然后使用向下的方向键时,焦点会跳到ListView中当前窗口的最下面一条,而不是焦点离开时的第一条。在ListView下方有Button的时候,向上移动焦点,也会出现类似的情况。
这个问题在Android的示例里面也有,ApiDemos->Views->Tabs->Content By Intent。这个示例里当使用方向键从list这个Tab向下移动焦点的时候,会跳过一屏的条目。
在网上搜了一下,仅仅有一个人提到了这个问题,但没有看到解答。
我查了一下源代码,实现设置焦点的代码是:
git://android.git.kernel.org/platform/frameworks/base.git›core›java›android›widget›ListView.java
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
int closetChildIndex = -1;
if (gainFocus && previouslyFocusedRect != null) {
previouslyFocusedRect.offset(mScrollX, mScrollY);
// figure out which item should be selected based on previously
// focused rect
Rect otherRect = mTempRect;
int minDistance = Integer.MAX_VALUE;
final int childCount = getChildCount();
final int firstPosition = mFirstPosition;
final ListAdapter adapter = mAdapter;
for (int i = 0; i < childCount; i++) {
// only consider selectable views
if (!adapter.isEnabled(firstPosition + i)) {
continue;
}
View other = getChildAt(i);
other.getDrawingRect(otherRect);
offsetDescendantRectToMyCoords(other, otherRect);
int distance = getDistance(previouslyFocusedRect, otherRect, direction);
if (distance < minDistance) {
minDistance = distance;
closetChildIndex = i;
}
}
}
if (closetChildIndex >= 0) {
setSelection(closetChildIndex + mFirstPosition);
} else {
requestLayout();
}
}
通过debug发现,previouslyFocusedRect在这里是ListView的,而不是之前焦点View的。在按向下键时,getDistance比较ListView的bottom和各个child的top,当然会选中离ListView下沿最近的。具体为什么会previouslyFocusedRect是ListView,我还没有深入分析。
一个解决办法
这不是一个根本解决的方法:写一个新的class,继承ListView,覆盖onFocusChanged。
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
if (gainFocus && previouslyFocusedRect != null) {
final ListAdapter adapter = getAdapter();
final int count = adapter.getCount();
switch (direction) {
case FOCUS_DOWN:
for (int i = 0; i < count; i++) {
if (!adapter.isEnabled(i)) {
continue;
}
setSelection(i);
break;
}
break;
case FOCUS_UP:
for (int i = count-1; i>=0; i--) {
if (!adapter.isEnabled(i)) {
continue;
}
setSelection(i);
break;
}
break;
default:
break;
}
}
}
在这里,我只处理了FOCUS_DOWN和FOCUS_UP。由于不能访问mFirstPosition,处理也做了简化:焦点从上方移下来时选择第一个能选择的,从下方移上来时选择最后一个能选择的。
感谢:http://sunote.info/2010/02/25/android-move-focus-to-listview/
分享到:
相关推荐
为了提高ListView的效率和应用程序的性能,在Android应用程序中不应该一次性加载ListView所要显示的全部信息,而是采取分批加载策略,随着用户的滑动,动态的从后台加载所需的数据,并渲染到ListView组件中,这样...
Android完美解决listview中多个edittext显示混乱问题,内含源码及apk文件
Android横向listview,列表左右可滑动,作为参考,很实用
Android 使用软引用解决listView卡顿问题
本文档时对android中LIstView的用法,初学者可以看看了解下
Android ListView添加两个Button焦点获取 listview 放弃焦点 让Button获取焦点 很简单的一个demo 点击相应 我没弄 也很简单 焦点都给你获取了 点击都不会做 我也没办法了 百度了这么久 自己写了个 希望能帮到大家
android异步远程解析json数据绑定到ListView上,响应地址也有了,分层思想写的,要是有什么异常之类的可以Q我
利用android studio实现listview嵌套listview,技术含量不是特别高,希望能帮助大家,这里就意思一下,给1分算啦
Android ListView边框圆角美化,可以用来仿iphone的个别界面。相当有用。美观。
通过读取网络的json数据,并显示到listview中,并具有加载更多的功能
注意 我用最新sdk(22 63) 可能有些同学不是最新 项目中没有自动生成appcompat v7 就把附件的项目导进去 ">最近在做android项目时 发现要在listView用到Button等各种点击事件 经过各种百度 发现有两个简单的方法...
滑动listview标题置顶,listview吸顶效果,安卓系统状态栏透明,有图有源码
android异步加载网络图片到ListView
最近研究android的最常用的控件ListView,感觉挺有趣的,包括Listview的循环机制,item重用机制,上下滑动刷新机制,然后做了一个焦点可滑动的ListView,不知道大家看过或者用过Apple TV没有,Apple TV里面的焦点都...
基于Eclipse开发平台,Android中使用ListView和三种适配器(ArrayAdaper,SimpleAdapter,BaseAdapter)实现数据的填充。
android关于listview之列表分组,像Q上一样显示列表项
android两列显示两个listview
我们在使用ListView的时候需要和数据进行绑定,那么问题来了,如何获取SQLite数据库中的数据并动态的显示到ListView当中呢?其实过程很简单:首先要获取SQLite数据(当然首先你要创建一个SQLite数据库并填写了一些...
android ListView item下载 ListView 进度条下载 ListView多个下载 android:ListView的局部刷新 Android中自定义Adapter实现ListView动态刷新进度条 android listview局部刷新和模拟应用下载
使用BaseAdapter自定义适配器,采用了回收converView和ViewHolder优化代码,并且解决了在ListView中使用Button时,ListView的itemClick不能被触发的问题。