Android ListView 的焦点问题
在项目开发中,在 ListView
的 Item
中放了一个 CheckBox
,然后就发现了一个重大的问题:
触发不了 ListView
的 onItemClick()
和 onItemLongClick()
方法
这个问题很严重,因为意味着 ListView
的 Item
点击不了,然后把 CheckBox
去掉之后又能点击了
所以,问题在于 CheckBox
拦截了这些方法
我们写一个 demo
来复现下
-
创建一个 空的 Android 项目
cn.twle.android.ListViewFocus
-
修改
activity_main.xml
添加一个 ListView<?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="8dp" android:orientation="vertical" > <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
-
定义列表中每一行的布局,在
res/layout
目录下新建一个文件listview_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="8dp" android:orientation="horizontal"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="8dp" android:textColor="#1D1D1C" android:textSize="20sp" android:layout_weight="3" /> <CheckBox android:id="@+id/checked" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout>
CheckBox
只是一个状态指示器 -
修改
MainActivity.java
package cn.twle.android.listviewfocus; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.SimpleAdapter; import android.widget.ListView; import android.widget.Toast; import android.widget.AdapterView; import android.view.View; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { private String[] langs = new String[]{ "Kotlin", "Scala", "Swift", "TypeScript", "Java", "Python", "PHP", "Perl", }; private Boolean[] checkeds = new Boolean[]{ true, false, true, false, true, false, true, false }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); List<Map<String, Object>> listitem = new ArrayList<Map<String, Object>>(); for (int i = 0; i < langs.length; i++) { Map<String, Object> showitem = new HashMap<String, Object>(); showitem.put("name", langs[i]); showitem.put("checked", checkeds[i]); listitem.add(showitem); } //创建一个 SimpleAdapter SimpleAdapter myAdapter = new SimpleAdapter(getApplicationContext(), listitem, R.layout.listview_item, new String[]{"name", "checked"}, new int[]{R.id.name, R.id.checked}); ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(myAdapter); listView.setOnItemClickListener(this); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(getApplicationContext(),"你点击了第" + position + "项",Toast.LENGTH_SHORT).show(); } }
运行范例后,点击部分区域没有效果
要怎么办呢 ?
解决办法有两个
-
为抢占了控件的组件设置
android:focusable="false"
或调用setFocusable(false)
为抢占了控件的组件设置
android:focusable="false"
之后,这个控件就不能再被点击了这个方法大部分能行得通,但是,
EditText
却不行如果为
EditText
设置了android:focusable="false"
,它可以获取焦点但是一下子又失去了焦点,而且也不会弹出小键盘因为它仍然可以点击啊...只是不能获得焦点,获得焦点有两种方式..自动获得和点击获得...
这时候只能加上
setFocusableInTouchMode(false);
了 -
item
根节点设置android:descendantFocusability="blocksDescendants"
设置这个属性的意思是禁止事件传递
这个属性还有其它的值
值 说明 beforeDescendants viewgroup 会优先其子类控件而获取到焦点 afterDescendants viewgroup 只有当其子类控件不需要获取焦点时才获取焦点 blocksDescendants viewgroup 会覆盖子类控件而直接获得焦点