【问题标题】:onTouchListener adding to all list elements instead of only oneonTouchListener 添加到所有列表元素而不是只添加一个
【发布时间】:2014-03-27 22:42:16
【问题描述】:

伙计们,我遇到了一个奇怪的问题:

在聊天应用程序中,我有一个 ListView 和一个 Adapter 来处理它。如果用户从图库发送图像,我将在气泡语音上显示缩略图并添加 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;
}

}

有什么想法吗?提前致谢

【问题讨论】:

  • 在哪里声明了“convertView”?
  • 我的错,我忘记了函数头。已编辑。

标签: android android-listview ontouchlistener listadapter


【解决方案1】:

在初始化imageView 后立即添加imageView.setOnTouchListener(null);。这将确保只有您想要附加侦听器的行才会拥有它。正如 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;
        }
    });

【讨论】:

  • 谢谢伙计,工作得很好......我很接近 Rob 的解释 :)
【解决方案2】:

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

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

【讨论】:

  • 感谢 RobP 的回答。我想我弄错了整个 getView 概念。我以为只有在添加视图时才调用它,仅此而已。不是这样吗?关于你说的黑客,你的意思是把一个 Uris 数组保存到应该打开的文件中,然后使用这个 ImageView 标记作为这个数组索引?如果没有,你能提供一个简单的例子吗?非常感谢:)
  • getView 是在视图准备好显示时调用的,是的 - 但是在 getView 中附加了一个侦听器,并且在实际触摸事件发生之前不会调用该侦听器。在触摸时,侦听器访问其父类 ConversationArrayAdapter 的消息成员变量。由于这行代码,该变量包含适配器最后处理的任何项目的消息:message = getItem(position);
  • 在 OnTouch 方法中设置一个断点,看看它何时被命中,变量“message”包含什么,这可能有助于理解。
  • 非常感谢,在 dcharms 发布它之前我真的很接近解决它......我没有意识到标签可能是一个对象并且正在传递索引......无论如何,你帮助了我找出问题所在,谢谢。 :)
猜你喜欢
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
  • 1970-01-01
  • 2015-04-24
  • 2012-05-20
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
相关资源
最近更新 更多