您的位置:首页 > 其它

ListView中为每个item设置监听器(转)

2014-03-21 11:36 134 查看
转自: http://blog.csdn.net/xujk2008/article/details/10049845
最近需要给ListView写一个监听器,在按住ListView中Item不松手的时候,改变Item的样式,使得被按住的Item背景色为灰,并显示跑马灯效果。因为需要具体到每个Item,所以首先想到了OnItemClickListener。但是稍微想想就知道这样是不行的,OnItemClickListener监听的是点击某个Item的动作,点击包括按下和松开两个部分,所以不用到达想要的效果。

于是想到用OnTouchListener监听按下的动作。但是,你知道我是会说但是的。OnTouchListener针对的是整个ListView,并没有提供被点击Item的位置参数,所以这样并不能达到改变单个Item显示效果的目的。顿时有种想掀桌的冲动,但是实验室的桌子我真的掀不动。于是去StackOverflow搜索,开始搜索不得法,没有找到想要的东西。难道老外们都不屑于问这种小白问题吗?不可能,我明明见过有人问Hello world为啥跑不出来之类的问题来着。几经变换关键词之后找到了一个和我问题很相似的提问。大概意思就是说
:“哥们儿,我原来遇到的问题和你现在遇到的这个问题贼拉想,唉呀妈呀,我告诉你咋整呗。你就自个儿写一个BaseAdapter子类,然后再getView()方法里加一个OnTouchListener就欧了,缸缸地好使。”之前要写跑马灯效果,所以自定义的适配器已经写过了,按照提问里说的办法加了OnTouchListener。

[java] view
plaincopy

package org.cdpsn.client.widget.wheel;

import java.util.List;

import java.util.Map;



import org.cdpsn.client.R;



import android.content.Context;

import android.graphics.Color;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.TextView;



public class ListItemAdapter extends BaseAdapter

{

private LayoutInflater inflater;

private List<Map<String, Object>> items;

private static int index = 0;



public ListItemAdapter(Context context, List<Map<String, Object>> items) {

super();

this.inflater = LayoutInflater.from(context);

this.items = items;

}

public void setIndex(int selected)

{

index = selected;

}



@Override

public int getCount() {

// TODO Auto-generated method stub

return items.size();

}



@Override

public Object getItem(int position) {

// TODO Auto-generated method stub

return items.get(position);

}



@Override

public long getItemId(int position) {

// TODO Auto-generated method stub

return position;

}



@Override

public View getView(final int position, View convertView, ViewGroup parent) {

// TODO Auto-generated method stub



System.out.println("Get in function getView.");

ViewHolder holder;

if(convertView == null)

{

convertView = inflater.inflate(R.layout.list_job, null);

holder = new ViewHolder();

holder.jobTitle = (TextView)convertView.findViewById(R.id.jobTitle);

holder.content = (TextView)convertView.findViewById(R.id.content);

holder.publishTimeText = (TextView)convertView.findViewById(R.id.publishTimeText);



convertView.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View view, MotionEvent motionEvent) {



if(motionEvent.getAction() == MotionEvent.ACTION_DOWN)

{

System.out.println("Item" + position + "pressed.");

ListItemAdapter.this.setIndex(position);

ListItemAdapter.this.notifyDataSetChanged();

}



return false;

}

});

}

else

{

holder = (ViewHolder)convertView.getTag();

}







if(index == position)

{

convertView.findViewById(R.id.content).setSelected(true);

// convertView.setBackgroundColor(Color.rgb(196, 215, 0));

convertView.setBackgroundColor(Color.LTGRAY);

holder.jobTitle.setTextColor(Color.WHITE);

holder.content.setTextColor(Color.WHITE);

holder.publishTimeText.setTextColor(Color.WHITE);

}

else

{

convertView.findViewById(R.id.content).setSelected(false);

convertView.setBackgroundColor(Color.WHITE);

holder.jobTitle.setTextColor(Color.BLACK);

holder.content.setTextColor(Color.BLACK);

holder.publishTimeText.setTextColor(Color.BLACK);

}



convertView.setTag(holder);

holder.jobTitle.setText( (String)items.get(position).get("jobTitle") );

holder.content.setText((String)items.get(position).get("content"));

holder.publishTimeText.setText((String)items.get(position).get("publishTimeText"));



return convertView;

}



private class ViewHolder {

private TextView jobTitle;

private TextView content;

private TextView publishTimeText;

}



}

试着跑了一下程序,似乎是可以的。但是多试了几次之后,发现还是有问题,当按住位置靠后的Item时,被按住的子项显示的效果并没有改变,改变的是位置靠前的子项。于是去搜索了一下getView的工作机制,发现convertView并不像我想象的那么简单。在配置适配器时,getView并没有为每一个Item配备一个convertView。设想一下,假如列表中有上百个Item,同时配备这么多convertView是很浪费资源的。所以convertView其实是可以循环利用的。也就是说,随着列表向下拉,屏幕上会显示新的子项,而老的子项会移出屏幕。这是,老的子项会把convertView交给新的子项使用,节省了资源。

再看上面的代码,只有在convertView为空时,才为convertView设置OnTouchListener监听器。这样,老的Item在移交convertView的同时,也把老的监听器移交给了新的Item。所以才会出现按住下面的子项,上面的子项变化样式的诡异情况。清楚了原理之后,把监听器的设置写在了判断convertView是否为空的程序片段的外面,代码如下:

[java] view
plaincopy

package org.cdpsn.client.widget.wheel;





import java.util.List;

import java.util.Map;



import org.cdpsn.client.R;



import android.content.Context;

import android.graphics.Color;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.TextView;



public class ListItemAdapter extends BaseAdapter

{

private LayoutInflater inflater;

private List<Map<String, Object>> items;

private static int index = 0;



public ListItemAdapter(Context context, List<Map<String, Object>> items) {

super();

this.inflater = LayoutInflater.from(context);

this.items = items;

}

public void setIndex(int selected)

{

index = selected;

}



@Override

public int getCount() {

// TODO Auto-generated method stub

return items.size();

}



@Override

public Object getItem(int position) {

// TODO Auto-generated method stub

return items.get(position);

}



@Override

public long getItemId(int position) {

// TODO Auto-generated method stub

return position;

}



@Override

public View getView(final int position, View convertView, ViewGroup parent) {

// TODO Auto-generated method stub



System.out.println("Get in function getView.");

ViewHolder holder;

if(convertView == null)

{

convertView = inflater.inflate(R.layout.list_job, null);

holder = new ViewHolder();

holder.jobTitle = (TextView)convertView.findViewById(R.id.jobTitle);

holder.content = (TextView)convertView.findViewById(R.id.content);

holder.publishTimeText = (TextView)convertView.findViewById(R.id.publishTimeText);

}

else

{

holder = (ViewHolder)convertView.getTag();

}



convertView.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View view, MotionEvent motionEvent) {



if(motionEvent.getAction() == MotionEvent.ACTION_DOWN)

{

System.out.println("Item" + position + "pressed.");

ListItemAdapter.this.setIndex(position);

ListItemAdapter.this.notifyDataSetChanged();

}



return false;

}

});



if(index == position)

{

convertView.findViewById(R.id.content).setSelected(true);

// convertView.setBackgroundColor(Color.rgb(196, 215, 0));

convertView.setBackgroundColor(Color.LTGRAY);

holder.jobTitle.setTextColor(Color.WHITE);

holder.content.setTextColor(Color.WHITE);

holder.publishTimeText.setTextColor(Color.WHITE);

}

else

{

convertView.findViewById(R.id.content).setSelected(false);

convertView.setBackgroundColor(Color.WHITE);

holder.jobTitle.setTextColor(Color.BLACK);

holder.content.setTextColor(Color.BLACK);

holder.publishTimeText.setTextColor(Color.BLACK);

}



convertView.setTag(holder);

holder.jobTitle.setText( (String)items.get(position).get("jobTitle") );

holder.content.setText((String)items.get(position).get("content"));

holder.publishTimeText.setText((String)items.get(position).get("publishTimeText"));



return convertView;

}



private class ViewHolder {

private TextView jobTitle;

private TextView content;

private TextView publishTimeText;

}



}

这样,无论新的convertView,还是移交过来的老的convertView,都设置了和当前Item位置相对应的OnTouchListener,自然也就达到了预想的效果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: