目录
当 ListView 中有一个 Button,CheckBox...等控件时,ListView 的 item 点击后触发不了 onItemClick() 方法,也触发不了 onItLemLongClick() 方法,为了方便示例,这里仅用 Button 作为 Item 演示。
出现这种问题的原因是,ListView 的焦点被其他控件抢了。
Demo
activity_list_view.xml
<?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:orientation="vertical"
tools:context=".ListViewActivity"
android:padding="10dp">
<ListView
android:id="@+id/id_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
activity_list_view_ques.xml(作为ListView Item)
<?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"
tools:context=".ListView_Ques"
android:padding="15dp"
android:gravity="center|top">
<Button
android:id="@+id/ques_but"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"/>
</LinearLayout>
ListView_Ques.java
package com.example.my_test;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ListView_Ques extends AppCompatActivity {
private ListView listView2;
private SimpleAdapter simpleAdapter2;
private List<Map<String,Object>> datas = new ArrayList<Map<String,Object>>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
listView2 = (ListView)findViewById(R.id.id_list_view);
Init_datas();
simpleAdapter2 = new SimpleAdapter(this,
datas,
R.layout.activity_list_view__ques,
new String[]{},
new int[]{R.id.list_Que});
listView2.setAdapter(simpleAdapter2);
listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(ListView_Ques.this,""+ simpleAdapter2.getItemId(i),Toast.LENGTH_SHORT).show();
}
});
}
//添加10个Button到ListView
private void Init_datas(){
for (int i = 1; i <= 10; i++)
{
Map map1 = new HashMap();
map1.put("Button",R.id.list_Que);
datas.add(map1);
}
}
}
效果
解决方法1:
ListView 中 Item 的 focusable 属性设置为 false
本例即在 activity_list_view_ques.xml 的 Button 中加入:
android:focusable="false"
解决方法2:
设置 item 的根布局的属性 android:descendantFocusability
该属性可选值有:
- beforeDescendants:viewgroup 会优先其子类控件而获取到焦点
- afterDescendants:viewgroup 只有当其子类控件不需要获取焦点时才获取焦点
- blocksDescendants:viewgroup 会覆盖子类控件而直接获得焦点
注意:如果你在 ListView 中使用了 EditText,使用以上方法会导致软件盘都无法弹出,解决方法可参考:传送门~
本文即在 activity_list_view_ques.xml 中增加 LinearLayout 属性
android:descendantFocusability="blocksDescendants"
效果图
这样只实现了 Item 的点击事件,但是点击 Button 依然无效,那么我们如何修改呢?
ListView 中嵌入布局的 Button 点击事件
上一篇 说到 BaseAdapter 的使用方法可简单理解为:adapter 先从 getCount ( ) 里确定数量,然后循环执行 getView ( ) 方法将条目一个一个绘制出来。
那么我们在绘制后加上点击事件监听的功能,是否可以实现呢?答案是肯定的。
由于 JAVA 中不支持多重继承,但是它提供了另外一种方式实现,即接口,因而我们要加上
implements View.OnClickListener
并重写它的 onClick() ,具体代码如下:
MyAdapter.java
package com.example.my_test;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.Toast;
import java.util.List;
import java.util.Map;
public class MyAdapter extends BaseAdapter implements View.OnClickListener{
//上下文
private Context context2;
//数据项
private List<? extends Map<String, ?>> datas2;
public MyAdapter(Context context2,List<? extends Map<String, ?>> datas2){
this.datas2 = datas2;
this.context2 = context2;
}
@Override
public int getCount() {
return datas2.size();
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public Object getItem(int i) {
return datas2.get(i);
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder2 viewHolder2 = null;
if(context2 == null){
context2 = viewGroup.getContext();
}
if (view == null){
view = LayoutInflater.from(context2).inflate(R.layout.activity_list_view__ques,null);
viewHolder2 = new ViewHolder2();
viewHolder2.mBtn = (Button)view.findViewById(R.id.ques_but);
view.setTag(viewHolder2);
}
//获取viewHolder2实例
viewHolder2 = (ViewHolder2)view.getTag();
//设置数据及监听器
viewHolder2.mBtn.setText("我是Button"+i);
viewHolder2.mBtn.setOnClickListener(this);
return view;
}
@Override
public void onClick(View view){
switch (view.getId()){
case R.id.ques_but:
// 仅输出 debug 调试
// Log.d("tag","Bth_onclick"+"view = " +view);
Toast.makeText(context2,"我是Button",Toast.LENGTH_SHORT).show();
}
}
static class ViewHolder2{
Button mBtn;
}
}
随后完成 ListView_Ques.java 的修改,将适配器更换为 MyAdapter
效果图
如何确定点击了那个Button
随着而来的问题是,我们可以判断是那个item被点击,却无法判断是那个item中的Button被点击。
解决的一个方法是:
使用 View 中的 setTag(Onbect)
在给多个 Button 添加一个监听器后,为每个 Button 设置不同的 setTag()。这个监听器就通过 getTag() 来分辨是哪个 Button 被按下。
效果图
ListView焦点的问题先到这了,学艺不精,如有理解不到位的地方,还请各位大佬指正。