2014-03-27 32 views
0

傢伙我有一個奇怪的問題:onTouchListener添加到所有列表元素,而不是隻有一個

在聊天應用程序,我有一個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; 
} 

}

任何想法?在此先感謝

+0

其中是「convertView」聲明? – brainmurphy1

+0

我的不好,我忘了功能標題。編輯。 –

回答

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; 
     } 
    }); 
+0

感謝的人,工作完美...我接近羅布解釋:) –

+0

很高興你能夠得到它的工作! – dharms

1

兩個問題: 1)您的OnTouchListener是一個內部類訪問外部類的消息屬性,它不斷處理不同的行時更改。當你處理觸摸事件時,適配器已經處理了最後一行數據,並停在那裏。它不像JavaScript關閉。每個imageView都需要一個不同的OnTouchListener,以顯示正確的項目。您可以通過創建一個OnTouchListener的子類來完成這個工作,您可以使用屬性對其進行初始化,以保持顯示正確的圖像路徑,或者可以像下面這樣做一個簡單的破解:在每個imageView上設置一個標記,並在OnTouchListener中使用該標記找出哪一行被點擊並以這種方式查找正確的圖像(使用標記作爲數組索引,或使用SQLiteCursor光標位置移動到或您有什麼)。

2)請記住,表中的行/視圖會被重新使用。因此,在您的適配器中,如果您在if語句分支中不應該有一個偵聽器的行,則需要刪除它,以防以前添加該行/視圖綁定到您的後備數據中的不同條目時。

+0

感謝您的答案RobP。我想我得到了整個getView概念錯誤。我以爲只有在添加視圖時纔會調用它,就是這樣。這不是那樣嗎?關於你說的黑客攻擊,你的意思是保留一系列Uris到應該打開的文件,然後使用這個ImageView標籤作爲這個數組索引?如果沒有,請提供一個簡單的例子嗎?非常感謝:) –

+0

當視圖準備好顯示時調用getView,是的 - 但是在getView中附加了一個監聽器,並且該監聽器在實際觸摸事件發生之前不會被調用。在觸摸時,監聽器訪問其父類ConversationArrayAdapter的消息成員變量。該變量包含適配器由於以下代碼行處理的任何項目的消息: message = getItem(position); – RobP

+0

在OnTouch方法內部設置斷點並查看它何時被命中,以及變量「message」包含的內容,這可能有助於理解它。 – RobP

相關問題