当前位置: 代码迷 >> Android >> 【Android】ListView与Button的共存有关问题解决
  详细解决方案

【Android】ListView与Button的共存有关问题解决

热度:98   发布时间:2016-05-01 20:31:33.0
【Android】ListView与Button的共存问题解决

这两天在捣鼓ListView widget,为了在ListView中加入Button这类的有 “点击” 事件的widget,请教了不少高手,感谢LandMark对我的认真讲解,下面把解决过程描述一下。
?
ListView 和 其它能触发点击事件的widget无法一起正常工作的原因是加入其它widget后,ListView的itemclick事件将无法触发,被其它widget的click事件屏蔽。
?
  • 首先,说明一下,ListView中每一行包括以下三项:
?
?? 一个ImageView, 一个TextView,一个ImageButton,依次排开。
?
以下是layout的内容,分为两部分:
  • res/layout/main.xml

?

<???xml?version?=?"1.0"?encoding?=?"utf-8"???>?
<?LinearLayout xmlns:android=?"http://schemas.android.com/apk/res/android"?
????android:layout_width=?"fill_parent"?android:layout_height=?"fill_parent"?
????android:padding=?"10dip"?android:orientation=?"vertical"?>?

????<?ListView android:id=?"@id/android:list"?android:layout_width=?"fill_parent"?
????????android:layout_height=?"fill_parent"?/?>?
<?/?LinearLayout>

因为继承了ListActivity,所以ListView 的id设置为"@id/android:list"是必须的

  • res/layout/lvitem.xml

注意:

<?RelativeLayout>中

android:descendantFocusability=?"blocksDescendants"

<?ImageButton>中

android:focusable?=?"false"

这两项的设置很关键,如果不设置,将导致ListView的ItemClick事件将无法触发,该事件被ImageButton的click事件屏蔽了。?

<???xml?version?=?"1.0"?encoding?=?"utf-8"???>?
<?RelativeLayout
??xmlns:android=?"http://schemas.android.com/apk/res/android"?
??android:layout_width=?"fill_parent"?
??android:layout_height=?"wrap_content"?
??android:padding=?"5dip"?
??android:descendantFocusability=?"blocksDescendants"?>?
??
??<?ImageView?
??????android:id=?"@+id/ItemImage"?
????android:layout_width=?"wrap_content"?
????android:layout_height=?"wrap_content"?
????android:padding=?"5dip"?
??/?>?
??
??
??<?!--?
??????把按钮背景设置为透明: ????android:background=?"#00000000"?
??????把按钮背景设置为半透明: ????android:background=?"#e0000000"?
??????-->?
??<?ImageButton?
?????android:id=?"@+id/ItemCloseWin"?
??????
?????android:layout_alignParentRight=?"true"?
?????android:layout_alignTop=?"@+id/ItemWinName"?
??????android:layout_alignBottom=?"@+id/ItemWinName"?
??????android:layout_width=?"wrap_content"?
??????android:layout_height=?"wrap_content"?
??????
??????android:background=?"#e0000000"?
??????android:gravity=?"left|center_vertical"?
??????android:focusable=?"false"?
??????android:src=?"@android:drawable/ic_menu_close_clear_cancel"?
??/?>?
??
??<?TextView?
??????android:id=?"@+id/ItemWinName"?
??????
??????android:layout_toRightOf=?"@+id/ItemImage"?
??????android:layout_toLeftOf=?"@+id/ItemCloseWin"?
??????android:layout_alignTop=?"@+id/ItemImage"?
??????android:layout_alignBottom=?"@+id/ItemImage"?
??????android:layout_width=?"wrap_content"?
??????android:layout_height=?"wrap_content"?
??????
??????android:gravity=?"left|center_vertical"?
??????android:textSize=?"20dip"?
??????android:text=?"title"?
??/?>?
????
???
<?/?RelativeLayout>

  • 接下来,我们看看继承ListActivity的实现

lvWithButtonExt中,为了能处理ImageButton的click事件,我继承了BaseAdapter类,并重新实现了getView()接口,在其中加入了Button的clicklistener,详见?lvButtonAdapter类的实现。

public?class?lvWithButtonExt?extends?ListActivity?{?
????@Override?
????protected?void?onCreate(?Bundle savedInstanceState)?{?
????????super?.?onCreate(?savedInstanceState)?;?
????????setContentView(?R.?layout?.?main)?;?

????????// 关联Layout中的ListView?
????????ListView?vncListView?=?(?ListView?)?findViewById(?android.?R.?id?.?list?)?;?
????????
????????// 生成动态数组,加入数据??
????????ArrayList?<?HashMap?<?String?,?Object?>?>?remoteWindowItem?=?new?ArrayList?<?HashMap<?String?,?Object?>?>?(?)?;?
????????for?(?int?i=?0;?i<?10;?i+?+?)?
????????{?
????????????HashMap?<?String?,?Object?>?map?=?new?HashMap?<?String?,?Object?>?(?)?;?
????????????map?.?put?(?"ItemImage"?,?R.?drawable.?firefox)?;?//图像资源的ID??
????????????map?.?put?(?"ItemWinName"?,?"Window ID "?+?i)?;?
????????????map?.?put?(?"ItemCloseWin"?,?android.?R.?drawable.?ic_menu_close_clear_cancel)?;
????????????remoteWindowItem.?add?(?map?)?;?
????????}?
????????
??????// 生成适配器的Item和动态数组对应的元素??
????????lvButtonAdapter listItemAdapter?=?new?lvButtonAdapter(?
????????????this?,?
????????????remoteWindowItem,?//数据源??
????????????R.?layout?.?lvitem,?//ListItem的XML实现?

????????????//动态数组与ImageItem对应的子项??
????????????new?String?[?]?{?"ItemImage"?,?"ItemWinName"?,?"ItemCloseWin"?}?,?
????????????//ImageItem的XML文件里面的一个ImageView,两个TextView ID??
????????????new?int?[?]?{?R.?id?.?ItemImage,?R.?id?.?ItemWinName,?R.?id?.?ItemCloseWin}?
????????)?;?
????????
????????vncListView.?setAdapter(?listItemAdapter)?;?
????}?

????@Override?
????protected?void?onListItemClick(?ListView?l,?View?v,?int?position?,?long?id?)?{?
????????// TODO Auto-generated method stub?
????????super?.?onListItemClick(?l,?v,?position?,?id?)?;?
????????l.?getItemAtPosition(?position?)?;?
????}?
}

  • 接下来,我们看看lvButtonAdapter?的实现

为了响应按钮的点击事件,首先要记录按钮的位置,然后为按钮设置clicklistener。

在重新实现的getView()接口中,我使用了lvButtonListener监听类,在构造函数中,记录行号,以便在OnClick接口中能准确的定位按钮所在的位置,进而对相应的行进行处理。

public?class?lvButtonAdapter?extends?BaseAdapter?{?
????private?class?buttonViewHolder?{?
????????ImageView?appIcon;?
????????TextView appName;?
????????ImageButton buttonClose;?
????}?
????
????private?ArrayList?<?HashMap?<?String?,?Object?>?>?mAppList;?
????private?LayoutInflater mInflater;?
????private?Context?mContext;?
????private?String?[?]?keyString;?
????private?int?[?]?valueViewID;?
????private?buttonViewHolder holder;?
????
????public?lvButtonAdapter(?Context?c,?ArrayList?<?HashMap?<?String?,?Object?>?>?appList,?intresource,?
????????????String?[?]?from?,?int?[?]?to)?{?
????????mAppList?=?appList;?
????????mContext?=?c;?
????????mInflater?=?(?LayoutInflater)?mContext.?getSystemService(?Context?.LAYOUT_INFLATER_SERVICE)?;?
????????keyString?=?new?String?[?from?.?length?]?;?
????????valueViewID?=?new?int?[?to.?length?]?;?
????????System?.?arraycopy?(?from?,?0,?keyString,?0,?from?.?length?)?;?
????????System?.?arraycopy?(?to,?0,?valueViewID,?0,?to.?length?)?;?
????}?
????
????@Override?
????public?int?getCount?(?)?{?
????????return?mAppList.?size?(?)?;?
????}?

????@Override?
????public?Object?getItem?(?int?position?)?{?
????????return?mAppList.?get?(?position?)?;?
????}?

????@Override?
????public?long?getItemId(?int?position?)?{?
????????return?position?;?
????}?

????public?void?removeItem?(?int?position?)?{?
????????mAppList.?remove?(?position?)?;?
????????this?.?notifyDataSetChanged(?)?;?
????}?
????
????@Override?
????public?View?getView?(?int?position?,?View?convertView,?ViewGroup?parent?)?{?
????????if?(?convertView?!?=?null?)?{?
????????????holder?=?(?buttonViewHolder)?convertView.?getTag?(?)?;?
????????}?else?{?
????????????convertView?=?mInflater.?inflate?(?R.?layout?.?lvitem,?null?)?;?
????????????holder?=?new?buttonViewHolder(?)?;?
????????????holder.?appIcon?=?(?ImageView?)?convertView.?findViewById(?valueViewID[?0]?)?;?
????????????holder.?appName?=?(?TextView)?convertView.?findViewById(?valueViewID[?1]?)?;?
????????????holder.?buttonClose?=?(?ImageButton)?convertView.?findViewById(?valueViewID[?2]?)?;?
????????????convertView.?setTag(?holder)?;?
????????}?
????????
????????HashMap?<?String?,?Object?>?appInfo?=?mAppList.?get?(?position?)?;?
????????if?(?appInfo?!?=?null?)?{?
????????????String?aname?=?(?String?)?appInfo.?get?(?keyString[?1]?)?;?
????????????int?mid?=?(?Integer?)?appInfo.?get?(?keyString[?0]?)?;?
????????????int?bid?=?(?Integer?)?appInfo.?get?(?keyString[?2]?)?;?
????????????holder.?appName.?setText?(?aname)?;?
????????????holder.?appIcon.?setImageDrawable(?holder.?appIcon.?getResources?(?)?.?getDrawable(mid)?)?;?
????????????holder.?buttonClose.?setImageDrawable(?holder.?buttonClose.?getResources?(?)?.getDrawable(?bid)?)?;?
????????????holder.?buttonClose.?setOnClickListener(?new?lvButtonListener(?position?)?)?;?
????????}?????????
????????return?convertView;?
????}?

????class?lvButtonListener?implements?OnClickListener?{?
????????private?int?position?;?

????????lvButtonListener(?int?pos)?{?
????????????position?=?pos;?
????????}?
????????
????????@Override?
????????public?void?onClick(?View?v)?{?
????????????int?vid=?v.?getId?(?)?;?
????????????if?(?vid?=?=?holder.?buttonClose.?getId?(?)?)?
????????????????removeItem?(?position?)?;?
????????}?
????}?
}

?

////////////////////////////////////////

备注1;?对于Android开发来说处理一些界面需要和Adapter适配器打交道,虽然Android自带了一些比如ArrayAdapter但是大多数情况下无法满足我们需要,所以就要从BaseAdapter派生一个类满足我们特殊的需要。

? 首先我们可能重写getView(),通过LayoutInflater的inflate方法映射一个自己定义的Layout布局xml加载或从xxxView中创建。这些大家可能滚瓜烂熟了但是仍然很多Android?开发者对于BaseAdapter中notifyDataSetChanged()方法不是很理解,notifyDataSetChanged方法通过一个外部的方法控制如果适配器的内容改变时需要强制调用getView来刷新每个Item的内容

  相关解决方案