论坛首页 移动开发技术论坛

Android ListView内部组件事件响应

浏览 15290 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-04-19   最后修改:2012-04-19

 


最近项目需要实现一个下载模块,界面布局就采用常见的ListView方式,实现的界面效果:


 

可是在事件监听的过程中出现问题了,内部组件如Button无法捕获到点击事件OnClick : 这个问题还好解决,通过给Button设定

 

android:focusable="false"

 然后给ListView的item布局文件的最顶层组件添加:

 

android:descendantFocusability="blocksDescendants"

 这样就可以同时相应Button的点击事件和Item的点击事件了。

 

但是,在点击后面的下载按钮时,会出现同时有两个按钮状态发生变化,ListView的Adapter的代码如下:

 

private class DownloadListAdapter extends BaseAdapter{
		private Context mContext;
		private LayoutInflater inflater;
		private List<Download> data;
		private int resource;
		
		public DownloadListAdapter(Context context,
				List<Download> data, int resource) {
			super();
			mContext = context;
			inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			this.data = data;
			this.resource = resource;
		}
		
		@Override
		public int getCount() {
			return data.size();
		}
		
		@Override
		public Object getItem(int position) {
			if(position < data.size()){
				return data.get(position);
			}
			return null;
		}
		
		@Override
		public long getItemId(int position) {
			return position;
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent){
			final Download down = (Download)getItem(position);
			if(convertView == null){
				convertView = inflater.inflate(resource, parent,false);
				
				ImageButton btn = (ImageButton)convertView.findViewById(R.id.down_pause);
				//添加事件监听
				btn.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						Log.d(TAG,"添加事件监听:"+ v.hashCode() +" - "+down.getId());
						if(down.getStatus() == Downloader.STATUS_RUNNING){
							Log.d(TAG, "暂停下载 : "+down.getId());
							mDownloader.pause(down.getId());
							down.setStatus(Downloader.STATUS_PAUSED);
						}else if(down.getStatus() == Downloader.STATUS_PAUSED){
							Log.d(TAG, "继续下载 : "+down.getId());
							mDownloader.continueDownload(down.getId());
							down.setStatus(Downloader.STATUS_RUNNING);
						}
						//DownloadListAdapter.this.notifyDataSetChanged();
						return ;
					}
				});
			}
			TextView nameText = (TextView)convertView.findViewById(R.id.down_name);
			ProgressBar bar = (ProgressBar)convertView.findViewById(R.id.down_progress);
			ImageButton btn = (ImageButton)convertView.findViewById(R.id.down_pause);
			
			int progress = (int)(down.getDownloadSize()*100/down.getSize());
			String name = down.getName();
			
			nameText.setText(name);
			bar.setProgress(progress);
			Log.d(TAG, "状态:"+down.getStatus());
			
			return convertView;
		}
 

事件监听器是在每个Item第一次初始化的时候添加的,而且也只添加了一次,同时日志跟踪,在点击最后一个按钮的时候,OnClick里面的日志也显示只调用了一次,但是界面的上的第一个按钮的状态也跟着发生变化。

 

纠结了很久都没弄清楚到底是哪里的问题。分析可能的原因:ImageButton btn =(ImageButton)convertView.findViewById(R.id.down_pause);是通过这种方式获得,而ListView里面所有的Item都共用一个布局文件,也就是上面的所有的convertView都是通过一个布局文件构造出来的,感觉这里会发生问题,但是貌似又没问题,在添加事件监听的过程中,打印的对应组件的hashCode又是不一样的,也就是每个按钮的事件监听器都是不一样的,这样分析之后又困惑了!

 

 

   发表时间:2012-04-20   最后修改:2012-04-20
建议你不要再listitem上使用 button 或者 imageButton , 使用imageview 没有问题的

button  和 imageButton  他们和listitem 的焦点事件有冲突(我是这么理解的)
我觉得如果使用imageview 不会出现问题的
0 请登录后投票
   发表时间:2012-04-20  
whao189 写道
建议你不要再listitem上使用 button 或者 imageButton , 使用imageview 没有问题的

button  和 imageButton  他们和listitem 的焦点事件有冲突(我是这么理解的)
我觉得如果使用imageview 不会出现问题的



这个建议不错,我看过安智市场的下载界面,感觉里面像是用的ImageView,而不是Button,所以后面打算修改为ImageView来查看效果!

非常感谢你的建议!
0 请登录后投票
   发表时间:2012-04-20   最后修改:2012-04-20
看来你不懂listview的运行原理啊 listview里面的item都是不回收的,所以你获得convertView对象可能就是你上次用的,是有状态的。
这个错误初学者很容易范,我以前也犯过这个错误,解决方法就是把item的所有状态都放在item的bean里,在getview里面从新设置convertView的状态(比如某个button是点击了还是没点击,某个图片背景等等)

而且在处理button里面的事件的时候也要做特殊处理,我的做法是 button.setTag(posation); 不然你的点击事件也会出现絮乱
0 请登录后投票
   发表时间:2012-04-20  
Cindy_Lee 写道
看来你不懂listview的运行原理啊 listview里面的item都是不回收的,所以你获得convertView对象可能就是你上次用的,是有状态的。
这个错误初学者很容易范,我以前也犯过这个错误,解决方法就是把item的所有状态都放在item的bean里,在getview里面从新设置convertView的状态(比如某个button是点击了还是没点击,某个图片背景等等)

而且在处理button里面的事件的时候也要做特殊处理,我的做法是 button.setTag(posation); 不然你的点击事件也会出现絮乱


多谢分析!对ListView的渲染机制我一直没认真琢磨过,很多时候都是会用就行,看来这样是不行的。
button.setTag(posation)这个做法不错,没有尝试过,之间一直不知道如何获取点击按钮对应的位置,可以用这个方法了!
0 请登录后投票
   发表时间:2012-04-21  
HI,你的适配器是继承BaseAdapter的吧,那样的话ListView的每行的控件就都能监听,比如你的Button。这个网上很多。

你点击Button的时候,取button的getPareten()就可以的到Button的外面一层的控件paretenView,然后通过paretenView.findViewByid的方法就可以找到你要的控件了。
0 请登录后投票
   发表时间:2012-04-21  
endual 写道
HI,你的适配器是继承BaseAdapter的吧,那样的话ListView的每行的控件就都能监听,比如你的Button。这个网上很多。

你点击Button的时候,取button的getPareten()就可以的到Button的外面一层的控件paretenView,然后通过paretenView.findViewByid的方法就可以找到你要的控件了。

现在 就是点击列表中的button出问题了,不过可以通过Cindy_Lee说的办法来改正这个问题,最近没时间完善,后面测试OK了再来改贴子。

这个方法getPareten 估计你拼错了,应该是getParent()
0 请登录后投票
   发表时间:2012-04-22  
我一般是把item的内的button组件去掉,将事件放到item本身上去,这样我觉得还好些。仅仅是个人观点。
0 请登录后投票
   发表时间:2012-04-23  
夜之son 写道
我一般是把item的内的button组件去掉,将事件放到item本身上去,这样我觉得还好些。仅仅是个人观点。

但是,我需要在item后面放置一个按钮用来控制item的状态
0 请登录后投票
   发表时间:2012-04-23  
aswang 写道
夜之son 写道
我一般是把item的内的button组件去掉,将事件放到item本身上去,这样我觉得还好些。仅仅是个人观点。

但是,我需要在item后面放置一个按钮用来控制item的状态


item本身就是一个view,你拿到了view,剩下的你想怎么变不就怎么变吗?
0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics