首先先看初次布局界面:
activity_main.xml布局:ListView的布局
-
<?xml version="1.0" encoding="utf-8"?> -
<RelativeLayout 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="com.qianfeng.listviewbutton.MainActivity"> -
<ListView -
android:id="@+id/mList" -
android:layout_width="match_parent" -
android:layout_height="match_parent"> -
</ListView> -
</RelativeLayout>
list_item.xml布局:ListView item的每个布局
-
<?xml version="1.0" encoding="utf-8"?> -
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" -
android:orientation="horizontal" android:layout_width="match_parent" -
android:layout_height="match_parent"> -
<TextView -
android:id="@+id/mTv" -
android:layout_marginTop="10dp" -
android:layout_width="wrap_content" -
android:layout_height="wrap_content" -
android:textSize="20sp" -
android:text="234" -
/> -
<Button -
android:id="@+id/mBtn" -
android:layout_width="wrap_content" -
android:layout_height="wrap_content" -
android:layout_alignParentRight="true" -
/> -
</RelativeLayout>
先看我们的初始代码:
MainActivity.java
-
public class MainActivity extends AppCompatActivity { -
//ListView控件 -
private ListView mList; -
//ListView数据源 -
private List<String> data; -
@Override -
protected void onCreate(Bundle savedInstanceState) { -
super.onCreate(savedInstanceState); -
setContentView(R.layout.activity_main); -
data = new ArrayList<>(); -
mList = (ListView)findViewById(R.id.mList); -
for(int i = 0; i < 20; i ++){ -
data.add("今天好手气" + i); -
} -
MyAdapter adapter = new MyAdapter(data); -
mList.setAdapter(adapter); -
//ListView item点击事件 -
mList.setOnItemClickListener(new ListView.OnItemClickListener(){ -
-
@Override -
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { -
Toast.makeText(MainActivity.this,"我是item点击事件 i = " + i + "l = " + l,Toast.LENGTH_SHORT).show(); -
} -
}); -
} -
}
MyAdapter.java
-
public class MyAdapter extends BaseAdapter implements View.OnClickListener { -
//上下文 -
private Context context; -
//数据项 -
private List<String> data; -
public MyAdapter(List<String> data){ -
this.data = data; -
} -
@Override -
public int getCount() { -
return data == null ? 0 : data.size(); -
} -
-
@Override -
public Object getItem(int i) { -
return data.get(i); -
} -
-
@Override -
public long getItemId(int i) { -
return i; -
} -
-
@Override -
public View getView(int i, View view, ViewGroup viewGroup) { -
ViewHolder viewHolder = null; -
if(context == null) -
context = viewGroup.getContext(); -
if(view == null){ -
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item,null); -
viewHolder = new ViewHolder(); -
viewHolder.mTv = (TextView)view.findViewById(R.id.mTv); -
viewHolder.mBtn = (Button)view.findViewById(R.id.mBtn); -
view.setTag(viewHolder); -
} -
//获取viewHolder实例 -
viewHolder = (ViewHolder)view.getTag(); -
//设置数据 -
viewHolder.mTv.setText(data.get(i)); -
//设置监听事件 -
viewHolder.mTv.setOnClickListener(this); -
//设置数据 -
viewHolder.mBtn.setText("点我点我"+ i); -
viewHolder.mBtn.setOnClickListener(this); -
return view; -
} -
-
@Override -
public void onClick(View view) { -
switch (view.getId()){ -
case R.id.mBtn: -
Log.d("tag", "Btn_onClick: " + "view = " + view); -
Toast.makeText(context,"我是按钮",Toast.LENGTH_SHORT).show(); -
break; -
case R.id.mTv: -
Log.d("tag", "Tv_onClick: " + "view = " + view); -
Toast.makeText(context,"我是文本",Toast.LENGTH_SHORT).show(); -
break; -
} -
} -
-
static class ViewHolder{ -
TextView mTv; -
Button mBtn; -
} -
-
}
通过上图我们可以看到,当鼠标第一次停留的地方,我点击item项时,没有任何反应,当点击按钮和文本的时候就会弹出吐司,那么为什么点击item会没有触发事件呢?怎样才能让item也有触发事件呢?
因为一个item布局中有按钮控件的话,按钮会获得焦点,而此时item就获取不到焦点,所以点击Item时不能触发其点击事件,如果想让item也有点击事件的话,则设置Button的焦点默认为false,则我们只需要在list_item.xml中的Button控件中加入android:focusable="false"
这样item就有了焦点,可以点击了
如下是改变焦点后的运行效果:
但是随之又有一个问题了,我们如何判断我们点击的是哪个item中的TextView和Button呢,因为目前的点击时间只能判断是TextView点击了,还是Button,或者item被点击了,除了item能知道是哪一项被点击了,其他两个却不知道是在哪个item中被点击了,所以我们需要将代码进行在此修改。只需要在MyAdapter中修改代码即可。基本思路是,我们可以将每个被点击的控件中设置一个标记,通过View中的setTag(int key, Object tag)方法设置即可,第一个key必须是一个资源id
资源id的添加
ids.xml
-
<?xml version="1.0" encoding="utf-8"?> -
<resources> -
<item name="btn" type="id"></item> -
<item name="tv" type="id"></item> -
</resources>
MyAdapter.java
-
public class MyAdapter extends BaseAdapter implements View.OnClickListener { -
private Context context; -
private List<String> data; -
public MyAdapter(List<String> data){ -
this.data = data; -
} -
@Override -
public int getCount() { -
return data == null ? 0 : data.size(); -
} -
@Override -
public Object getItem(int i) { -
return data.get(i); -
} -
-
@Override -
public long getItemId(int i) { -
return i; -
} -
-
@Override -
public View getView(int i, View view, ViewGroup viewGroup) { -
ViewHolder viewHolder = null; -
if(context == null) -
context = viewGroup.getContext(); -
if(view == null){ -
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_item,null); -
viewHolder = new ViewHolder(); -
viewHolder.mTv = (TextView)view.findViewById(R.id.mTv); -
viewHolder.mBtn = (Button)view.findViewById(R.id.mBtn); -
view.setTag(viewHolder); -
} -
viewHolder = (ViewHolder)view.getTag(); -
//设置tag标记 -
viewHolder.mBtn.setTag(R.id.btn,i);//添加此代码 -
viewHolder.mBtn.setText("点我点我"+ i); -
viewHolder.mBtn.setOnClickListener(this); -
viewHolder.mTv.setText(data.get(i)); -
//设置tag标记 -
viewHolder.mTv.setTag(R.id.tv,i);//添加此代码 -
viewHolder.mTv.setOnClickListener(this); -
return view; -
} -
@Override -
public void onClick(View view) { -
switch (view.getId()){ -
case R.id.mBtn: -
int b = (int) view.getTag(R.id.btn); -
Toast.makeText(context,"我是按钮 " + b,Toast.LENGTH_SHORT).show(); -
break; -
case R.id.mTv: -
int t = (int)view.getTag(R.id.tv); -
Toast.makeText(context,"我是文本" + t,Toast.LENGTH_SHORT).show(); -
break; -
} -
} -
static class ViewHolder{ -
TextView mTv; -
Button mBtn; -
} -
}
基本已经实现了,案例比较简单,适合初学者。
阅读全文
如果你是用ImageView,还是会出现item点击无效,接着看下面:
Android开发中在ListView中经常有Item的点击事件及Button或ImageButton等需要被点击的事件之间的处理方法
解决的办法,在ListView的Item的xml文件中添加如下属性:
1)整个xml文件的根元素如LinearLayout中添加属性android:descendantFocusability="blocksDescendants"
2)被点击的控件如ImageButton中添加属性android:focusable="false"和android:clickable="true"
android:descendantFocusability=””方法解析:
开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点。原因多半是由于在你自己定义的Item中存在诸如ImageButton,Button,CheckBox等子控件(也可以说是Button或者Checkable的子类控件),此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应。
这时候就可以使用descendantFocusability来解决啦,API描述如下:
android:descendantFocusability
Defines the relationship between the ViewGroup and its descendants when looking for a View to take focus.
Must be one of the following constant values.
该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系。
属性的值有三种:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
通常我们用到的是第三种,即在Item布局的根布局加上android:descendantFocusability=”blocksDescendants”的属性就好了,至此listview点击的灵异事件告一段落。心得:遇到不会不懂的地方除了网上查询资料之外,也可以多多去尝试每种属性的作用,多阅读官方文档(我始终觉得还是读原文的比翻译的理解的会更好)。