自定义适配器:获取膨胀列表视图中单击项目的项目编号

时间:2012-02-05 18:07:18

标签: android android-adapter custom-adapter

我有一个自定义baseadapter,它会对某些图像进行一些延迟加载,然后对布局进行充气,以便最终得到一个listview,其中我将图像和文本放在一行中。

当用户按下列表视图中的一个项目时,例如项目0(顶部项目),我想显示一个包含特定内容的对话框。此内容取决于项目编号 - 因此项目0显示的内容与项目1不同,依此类推。

以下是自定义适配器的getView方法:

public View getView(int position, View convertView, ViewGroup parent)
{
    View vi=convertView;        
    if(convertView==null)
    {
        vi = inflater.inflate(R.layout.facebook_item, null);                        
        vi.setClickable(true);
        vi.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {                   
                String s = "test";
                Toast.makeText(myContext, s, Toast.LENGTH_SHORT).show();
            }
        });
    }        

    TextView text=(TextView)vi.findViewById(R.id.text);
    ImageView image=(ImageView)vi.findViewById(R.id.image);
    text.setText(msg[position]);
    text.getLineCount();
    imageLoader.DisplayImage(data[position], image);
    return vi;
}

这里重要的是onClick方法中发生了什么。我想有一个item参数,但这对于这个OnClickListener是不可能的。正常的列表视图是可能的,我知道。

那么 - 如何确定点击了哪个项目?

PS:我试图考虑使用某种vi.setTag(<<number>>);,但如果没有为列表视图的所有项目设置相同的标记,我不知道如何做到这一点。

2 个答案:

答案 0 :(得分:5)

为什么不在ListView本身上使用onItemClickListener?

您的适配器应包含一个对象类型的列表(没有严格的规则,但它有助于更​​轻松地管理项目)。例如

class MsgObject{
    String msg;
    String data

    //TODO Getters/Setters goes here
}

然后您的CustomAdapter将只包含

List<MsgObject> objectList;

然后你的getView看起来与此类似

    MsgObject m = (MsgObject)getObject(position);
    TextView text=(TextView)vi.findViewById(R.id.text);
    ImageView image=(ImageView)vi.findViewById(R.id.image);
    text.setText(m.getMsg());
    text.getLineCount();
    imageLoader.DisplayImage(m.getData(), image);
    //Tag id is predefined in xml
    vi.setTag(R.id.listItemTag, m);
    return vi;

现在,您的视图将把它作为一个对象处理,而不是一个具有多个值的布局。

然后我们将所有点击操作移动到ListView所在的Activity。

listView.setOnItemClickListener(){
    new AdapterView.OnItemClickListener(){

        @override
        public onItemClick(AdapterView<?> parent, View view, int position, long id){
            MsgObject m = (MsgObject)view.getTag(R.id.listItemTag);
            Toast.makeText(context, "Pos[" + position 
                + "] clicked, with msg: " + m.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

};

这是我使用Lazy加载ImageView的ListView的方式。然后,您将能够访问与该视图关联的对象以及单击的位置。

如果您希望将msg和数据分开。你可以使用setTag(id,obj);对于对象等等。

setTag(R.id.listItemMsg, msg[position]);
setTag(R.id.listItemData, data[position]);

更新:我的CustomAdapter示例

/**
 * Adapter for displaying Place selection list.
 * @author Poohdish Rattanavijai
 *
 */    
public class PlaceAdapter extends BaseAdapter {
    private static final String TAG = PlaceAdapter.class.getSimpleName();
    private List<PlaceVO> list; // <-- list of PlaceVOs
    private Context context;
    private int viewResourceId;

    /**
     * 
     * @param context Context
     * @param viewResourceId Layout ID for each item
     * @param list resource list to populate
     */
    public PlaceAdapter(Context context, int viewResourceId, List<PlaceVO> list){
        this.context = context;
        this.viewResourceId = viewResourceId;
        this.list = list;
    }

    /**
     * Number of result in the list plus one (for +add at the last item)
     */
    @Override
    public int getCount() {

        if(null != list){
            return list.size();
        }

        return 1;
    }

    @Override
    public Object getItem(int arg0) {
        if(null != list){
            try {
                return list.get(arg0);
            } catch (IndexOutOfBoundsException e) {
                return null;
            }
        }
        return null;
    }

    @Override
    public long getItemId(int position) {
//      if(null != list){
//          try {
//              return list.get(position).getId();
//          } catch (IndexOutOfBoundsException e) {
//              return 0;
//          }
//      }
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(null == convertView){
            /**
             * View does not exist, populate.
             */
            LayoutInflater inflater = LayoutInflater.from(this.context);
            convertView = inflater.inflate(this.viewResourceId, parent, false);
        }
        ViewHolder holder = (ViewHolder)convertView.getTag(R.id.adpter_view);

        if(null == holder){
            Log.d(TAG, "holder not found, init.");
            /**
             * ViewHolder does not exists for this view; create and assign respective view.
             */
            holder = new ViewHolder();
            holder.title = (TextView) convertView.findViewById(R.id.title);
            holder.details = (TextView) convertView.findViewById(R.id.details);
            holder.icon = (ImageView) convertView.findViewById(R.id.icon);
            holder.progress = (ProgressBar) convertView.findViewById(R.id.progress);
        }

        PlaceVO v = (PlaceVO)getItem(position); // <-- GetItem

        if(null != v){
            Log.d(TAG, "Place not null");
            if(HelperUtil.IsNotNullOrEmpty(v.getName())){
                Log.d(TAG, "Name: " + v.getName());
                holder.title.setText(v.getName());
            }

            if(HelperUtil.IsNotNullOrEmpty(v.getVicinity())){
                Log.d(TAG, "details: " + v.getVicinity());
                holder.details.setText(v.getVicinity());
            }

            if(HelperUtil.IsNotNullOrEmpty(v.getIcon())){
                holder.progress.setVisibility(View.VISIBLE);
                holder.icon.setVisibility(View.GONE);
                            //TODO Initialize LazyLoad
            }else{
                holder.progress.setVisibility(View.VISIBLE);
                holder.icon.setVisibility(View.GONE);
            }
        }
            // Two tags, one for holder, another for the VO
        convertView.setTag(R.id.adpter_view, holder);
        convertView.setTag(R.id.adpter_object, v);
        return convertView;
    }

    static class ViewHolder{
        TextView title;
        TextView details;
        ImageView icon;
        ProgressBar progress;
    }
}

内部活动我使用

处理项目点击操作
OnItemClickListener itemClick = new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1,
                    int arg2, long arg3) {
                PlaceVO v = (PlaceVO)arg1.getTag(R.id.adpter_object); // <-- get object using tag.
                switchToPlaceScreen(v);
            }
        };
listView.setOnItemClickListener(itemClick);

希望这能回答你的问题:)

答案 1 :(得分:1)

text.setText(msg[position]);
text.getLineCount();
imageLoader.DisplayImage(data[position], image);

在创建自定义适配器时,您希望尽可能使用getItem(int position)引用项目。避免使用您在Adapter构造函数中传递的实际数组来引用它。

尝试覆盖适配器上的getItem(int position)getItemId(int position),并在getView内使用它代替数组。