发现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/
分享到:
相关推荐
解决这个问题的方法是在子View的XML布局中添加`android:clickable="false"`或`android:focusable="false"`,或者在代码中设置`setClickable(false)`和`setFocusable(false)`,使得点击事件能传递到ListView。...
在Android开发中,ListView是一个非常常见的组件,用于展示大量数据的列表形式。它允许用户滚动浏览,同时提供了可定制的视图复用机制,以优化性能。然而,当ListView内部包含EditText时,开发者可能会遇到一些挑战...
当用户在EditText中输入完毕后按回车键,可以通过设置KeyListener或TextWatcher来处理键盘事件,焦点移到下一列的EditText,或者根据业务逻辑执行相应的操作。 4. **处理点击事件**:可能需要为ListView添加...
在Android开发中,QQListView是一种常见的可滑动并带有多种操作功能的列表控件,它扩展了Android原生的ListView,增加了诸如滑动删除、置顶等交互效果。本教程将详细讲解如何实现"防QQListView滑动置顶删除功能"。 ...
首先,Gallery2应用的核心是Android的ListView组件,它是Android中用于展示可滚动列表的视图。在这个应用中,ListView被用来展示图片的缩略图,这涉及到自定义Adapter,用于将数据集(如图片路径)转换为ListView...
5. **ListView集成**:如果控件是在ListView中,那么需要处理ListView的滚动和焦点问题。ListView有自己的焦点机制,通常情况下,焦点会跟随列表项的可见性变化。因此,需要确保在动画完成后,列表项的位置和焦点...
在Android开发中,View是构建用户界面的基本元素,它代表屏幕上的一个可视组件,比如按钮、文本框等。本文将基于Android 2.2 API的中文文档,深入探讨View类的相关知识点。 首先,View类是所有UI元素的基类,它负责...
在 Android TV 开发中,焦点记忆功能是一个常见的需求,特别是在列表控件中,例如 ListView 或 RecyclerView。当用户离开列表项时,焦点需要记忆当前位置,以便在返回时能够定位到原来的项目上。下面是实现焦点记忆...
在Android开发中,Button控件是用户界面中最基础也是最重要的元素之一,它允许用户执行特定的操作或触发事件。本文将通过“Android 源码Button 经典实例”这一主题,深入探讨Button的使用方法、源码分析以及实战案例...
在Android开发中,`TextView` 是一个非常基础且重要的组件,通常用于显示单行或多行文本。在某些场景下,我们可能希望让`TextView`中的文字实现上下滚动的效果,以展示更多的信息或者吸引用户的注意力。这篇博文中,...
在Android应用开发中,经常会遇到一个问题,即当用户在输入框中输入时,弹出的软键盘会遮挡部分屏幕内容,尤其是对于登录或注册等需要填写多项信息的界面,这种情况严重影响了用户体验。为了解决这个问题,Android...
- 通过子线程发送消息到主线程的消息队列中,主线程中的Looper不断从消息队列中取出消息,并通过Handler分发到对应的处理方法。 #### 5. Activity、Intent、Service的关系 - **Activity**是用户界面的基本组成部分...
适配器(Adapter)在Android中主要用于将数据绑定到组件上,比如ListView,将数据集转化为列表项显示,而不仅仅是存储数据或者解析数据。 Matrix类是用来处理二维矩阵,用于图像变换,如缩放、旋转或平移,对内存中...
- **singleTask**:如果Activity实例已经存在于任务栈中,就会复用该实例,并将其移至栈顶;否则,创建新实例。 - **singleInstance**:总是创建一个新的实例,且独立于其他Activity之外运行。 #### 8. Intent的...
在Android开发中,`PopupWindow`是一个非常实用的组件,它允许我们在主界面之上显示一个浮动的窗口,常用于创建下拉菜单、悬浮提示框等。这个“android 弹出窗口动画demo”就是一个示例,展示了如何在Android应用中...
在Android开发中,"android--gallery走廊效果图片查看器"是一种常见的用户界面组件,用于展示图片,它提供了类似走廊或画廊的滚动效果,让用户能够优雅地浏览一系列图像。这个组件在早期版本的Android SDK中被称为`...
- **Single Task**:如果Intent对应的Activity实例存在,则将其移到栈顶并复用;否则新建一个实例。 #### 9. Activity的生命周期 Activity的生命周期包括以下几个关键阶段: - **onCreate()**:首次创建Activity...
### Google Android SDK 开发...以上是《Google Android SDK开发范例大全》中部分章节的主要知识点概述,这些知识点覆盖了Android应用开发的基础到高级技术,对于希望深入了解Android开发的人来说是非常宝贵的资源。
### 2011 Android技术面试知识点详解 #### 1. Android的四大组件及其作用 - **Activity**:这是...以上内容涵盖了2011年Android技术面试中常见的知识点,有助于准备相关面试或复习Android开发的基本概念和技术要点。