onTouchListener添加到所有列表元素而不是仅一个

时间:2014-03-27 22:42:17

标签: android android-listview ontouchlistener listadapter

伙计我有一个奇怪的问题:

在聊天应用程序中,我有一个ListView和一个适配器来处理它。如果用户从图库发送图像,我将在气泡语音上显示缩略图,并添加onTouchListener以全屏打开此图像。问题是:当我添加事件监听器时,它会添加到我的所有ImageViews!因此,如果我点击最后一个imageView,它会在整个屏幕上显示正确的图像,但之前的所有图像都显示相同的图像。我已经多次查看了代码,但我看不出问题。有人可以帮忙吗?

我的适配器:

public class ConversationArrayAdapter extends ArrayAdapter<Message> {

private TextView messageView;
private TextView timeView;
private TextView confView;
private ImageView imageView;
private LinearLayout timeConfView;
private List<Message> messages = new ArrayList<Message>();
private WindowManager wm;
private Display display;
private RelativeLayout.LayoutParams params;
private Context context;
private Message message;

public ConversationArrayAdapter(Context context, int textViewResourceId) {
    super(context, textViewResourceId);

    this.context = context;
    wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    display = wm.getDefaultDisplay();
}

public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    if (row == null) {
        LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.list_item_message, parent, false);
    }

    message = getItem(position);

    messageView = (TextView) row.findViewById(R.id.message);
    messageView.setText(message.message);
    messageView.setBackgroundResource(message.left ? R.drawable.anonymous : R.drawable.me);

    timeView = (TextView) row.findViewById(R.id.time);
    timeView.setText(message.time);

    confView = (TextView) row.findViewById(R.id.confirmation);
    confView.setText(message.conf);

    timeConfView = (LinearLayout) row.findViewById(R.id.timeConfWrapper);

    imageView = (ImageView) row.findViewById(R.id.imageUploaded);

    messageView.setMaxWidth(display.getWidth() - (30*display.getWidth()/100));
    imageView.setMaxWidth(display.getWidth() - (30*display.getWidth()/100));
    imageView.setMaxHeight(display.getHeight() - (70*display.getHeight()/100));
    params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
    params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
    messageView.setLayoutParams(params);
    messageView.setPadding(
                (int)(10 * context.getResources().getDisplayMetrics().density),
                (int)(5 * context.getResources().getDisplayMetrics().density), 
                (int)(15 * context.getResources().getDisplayMetrics().density), 
                (int)(6 * context.getResources().getDisplayMetrics().density));
        messageView.requestFocus();

    if (!message.image) {
        params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.LEFT_OF, R.id.message);
        params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
        timeConfView.setLayoutParams(params);
        timeConfView.setPadding(0, 0, (int)(10 * context.getResources().getDisplayMetrics().density), 0);
    } else {

        imageView.setPadding(
                    (int)(5 * context.getResources().getDisplayMetrics().density),
                    (int)(5 * context.getResources().getDisplayMetrics().density), 
                    (int)(10 * context.getResources().getDisplayMetrics().density), 
                    (int)(5 * context.getResources().getDisplayMetrics().density));
        imageView.requestFocus();

        messageView.setVisibility(TextView.INVISIBLE);
        imageView.setVisibility(ImageView.VISIBLE);

        params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.LEFT_OF, R.id.imageUploaded);
        params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
        timeConfView.setLayoutParams(params);
        timeConfView.setPadding(0, 0, (int)(10 * context.getResources().getDisplayMetrics().density), 0);

        imageView.setImageBitmap(message.bitImage);

        imageView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Uri imgUri = Uri.parse("file://" + message.imagePath);
                Intent intent = new Intent(); 
                    intent.setAction(android.content.Intent.ACTION_VIEW);
                intent.setData(imgUri);
                intent.setDataAndType(imgUri, "image/*");
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
                return true;
            }
        });

        confView.setVisibility(TextView.VISIBLE);
    }

    return row;
}

@Override
public void add(Message object) {
    messages.add(object);
    super.add(object);
}

我如何在活动中使用它:

 @Override
 public void onActivityResult(int requestCode, int resultCode, Intent data) {
      // Checking the request for gallery and a lot of stuff and generating a bitmap with the filePath
      Message msg = new Message(false, message.getText().toString(), DateFormat.getTimeInstance().format(new Date()).substring(0,5), true, bitmap, filePath);
      adapter.add(msg);
}

我的按摩课程:

package br.com.unichat.classes;

import android.graphics.Bitmap;

public class Message {
public boolean left;
public boolean image;
public String message;
public String time;
public String conf;
public String imagePath;
public Bitmap bitImage;

public Message(boolean left, String comment, String time) {
    super();
    this.left = left;
    this.message = comment;
    this.time = time;
    this.conf = "·";
    this.image = false;
    this.bitImage = null;
}

public Message(boolean left, String comment, String time, boolean image, Bitmap bitImage, String path) {
    super();
    this.left = left;
    this.message = comment;
    this.time = time;
    this.conf = "·";
    this.image = image;
    this.bitImage = bitImage;
    this.imagePath = path;
}

}

有什么想法吗?提前致谢

2 个答案:

答案 0 :(得分:1)

两个问题: 1)您的OnTouchListener是一个内部类,它访问外部类的message属性,该属性在处理不同的行时不断变化。当您处理触摸事件时,适配器已处理数据的最后一行,并停在那里。它不像JavaScript闭包。每个imageView都需要一个不同的OnTouchListener,它将在触摸时显示正确的项目。您可以通过创建一个OnTouchListener的子类来实现这一点,该子类使用属性进行初始化以保持正确的图像路径显示,或者您可以执行以下简单的hack:在每个imageView上设置标记,并在OnTouchListener中使用该标记找出哪一行被点击并以那种方式查找正确的图像(使用标记作为数组索引,或使用SQLiteCursor光标位置移动到,或者你有什么)。

2)请记住,表格中的行/视图会被重复使用。因此,在您的适配器中,如果您在不应该有侦听器的行的if语句分支中,则需要删除它,以防先前在该行/视图绑定到后备数据中的其他条目时添加它

答案 1 :(得分:1)

初始化imageView.setOnTouchListener(null);后立即添加imageView。这将确保只有您想要附加侦听器的行才能拥有它。正如RobP所说,你的观点在屏幕上显示时会被重复使用,因此之前的OnTouchListener可能仍会被附加。

您还需要跟踪用户点击图片时要使用的消息。为此,您可以使用setTag();。您生成的代码应如下所示:

imageView.setTag(message);
imageView.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Message messageForThisRow = (Message)v.getTag();
            Uri imgUri = Uri.parse("file://" + messageForThisRow.imagePath);
            Intent intent = new Intent(); 
                intent.setAction(android.content.Intent.ACTION_VIEW);
            intent.setData(imgUri);
            intent.setDataAndType(imgUri, "image/*");
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
            return true;
        }
    });