2013-04-01 6 views
0

Я столкнулся с очень странным поведением ListView. У меня есть приложение для чата, которое использует ListView и пользовательскую реализацию BaseAdapter для отображения сообщений.ListView изменения фона элемента в зависимости от положения прокрутки

Идея, которую я имел, заключалась в том, чтобы затенять сообщения от «местного» пользователя серыми и иметь сообщения от «удаленного» пользователя белого цвета, чтобы помочь пользователю провести различие между ними. Два скриншота ниже показывают, что происходит. Вторая - это то же самое действие, xml и т. Д., Просто прокручивается немного.

прокручивается вверх:

scrolled up image

прокрутила:

scrolled down image

Посмотрите на сообщение, отправленное "Me" @ 23:05. Когда наверху он не контрастирует со своими соседями, но когда он прокручивается на дно, разница очевидна. Это происходит на схеме 4 и 7 на 4.2.2, а GS3 работает 4.1.2.

Вот XML для одного из элементов ListView:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/activity_view_conversation_message_list_item_wrapper" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:paddingBottom="2dp" 
    android:paddingLeft="5dp" 
    android:paddingRight="10dp" > 


    <ImageView 
     android:id="@+id/activity_view_conversation_message_list_item_user_image" 
     android:layout_width="50dp" 
     android:layout_height="50dp" 
     android:layout_alignParentLeft="true" 
     android:layout_marginTop="5dp" 
     android:src="@drawable/default_user_image" /> 

    <TextView 
     android:id="@+id/activity_view_conversation_message_list_item_heading" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_marginLeft="10dp" 
     android:layout_marginTop="1dp" 
     android:layout_toRightOf="@+id/activity_view_conversation_message_list_item_user_image" 
     android:text="Martyn" 
     android:textColor="#000000" 
     android:textSize="18sp" 
     android:textStyle="bold" /> 

    <TextView 
     android:id="@+id/activity_view_conversation_message_list_item_contents" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_below="@+id/activity_view_conversation_message_list_item_heading" 
     android:layout_marginLeft="10dp" 
     android:layout_marginRight="5dp" 
     android:layout_marginTop="2dp" 
     android:layout_toLeftOf="@+id/activity_view_conversation_message_list_item_ack" 
     android:layout_toRightOf="@+id/activity_view_conversation_message_list_item_user_image" 
     android:text="Hello this is some text" 
     android:textColor="#333333" 
     android:textIsSelectable="true" 
     android:textSize="18sp" /> 

    <TextView 
     android:id="@+id/activity_view_conversation_message_list_item_time" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentTop="true" 
     android:layout_marginTop="2dp" 
     android:paddingLeft="5dp" 
     android:paddingRight="5dp" 
     android:paddingTop="2dp" 
     android:text="12:08" 
     android:textSize="14sp" /> 

    <ImageView 
     android:id="@+id/activity_view_conversation_message_list_item_ack" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignTop="@+id/activity_view_conversation_message_list_item_time" 
     android:layout_marginRight="2dp" 
     android:layout_marginTop="8dp" 
     android:layout_toLeftOf="@+id/activity_view_conversation_message_list_item_time" 
     android:src="@drawable/red_dot_8dp" /> 

</RelativeLayout> 

А вот где я поставил цвет RelativeLayout:

if(localUserId.equals(remoteUserId)){ 
    itemLayout.setBackgroundColor(Color.parseColor("#F9F9F9")); 
} 

Этот код работает внутри GetView() метод моего адаптера.

Я искал это честно и ничего не понял, есть много вопросов о проблеме android: cacheColorHint, но я не думаю, что это то, что происходит здесь.

Кто-нибудь сталкивался с этим раньше? Я в тупике!

EDIT: Вот код baseadapter:

public class MessageListAdapter extends BaseAdapter { 
    private ArrayList<Message> messageList; 
    Context context; 

    /** 
    * Constructor 
    * @param newConversationsList An ArrayList of Conversation objects that this adapter will use 
    * @param newContext   The context of the activity that instantiated this adapter 
    */ 
    MessageListAdapter(ArrayList<Message> newMessageList, Context newContext){ 
     messageList = newMessageList; 
     //reload(); 
     context = newContext; 
    } 

    public int getCount() { 
     return messageList.size(); 
    } 

    public Object getItem(int position) { 
     return messageList.get(position); 
    } 

    public long getItemId(int position) { 
     return position; 
    } 

    /** 
    * Adds a message to the chat list 
    * @param message  A Message object containing all the message's information 
    */ 
    public void add(Message message){ 
     //nMessagesToShow++;  //A new message has been added, so increase the number to show by one 
     Log.d(TAG, "COUNT: "+getCount()); 
     //refresh(); 
    } 

    public void refresh(){ 
     this.notifyDataSetChanged(); 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     View view = convertView; 

     if(view!=null){ 
      //return view; 
     } 

     LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

     //Get the Message object from the list 
     Message message = messageList.get(position); 

     //Get the data from the message 
     String senderId = message.getFromUser(); 
     int messageType = message.getType(); 

     String senderFirstName; 

     ImageView userImage, messageImage; 
     TextView messageHeading, messageBody; 

     switch(messageType){ 
     case Message.MESSAGE_TYPE_TEXT:    //Standard text message 
      //The layout we inflate for this list item will vary depending on whether this message has the same sender as the previous 
      if(position>0 && senderId.equals(messageList.get(position-1).getFromUser())){  //True if this is not the first message AND the sender id matches that of the previous message    
       view = vi.inflate(R.layout.activity_view_conversation_message_list_item_alternate, null);  //Inflate an alternate version of the list item which has no heading or user image 
      } 
      else{  //This is the first message OR the sender id is different to the previous    
       view = vi.inflate(R.layout.activity_view_conversation_message_list_item, null);     //Inflate the standard version of the layout 

       userImage = (ImageView) view.findViewById(R.id.activity_view_conversation_message_list_item_user_image); 
       messageHeading = (TextView) view.findViewById(R.id.activity_view_conversation_message_list_item_heading); 

       //Use the sender's ID to get the sender's image and first name 
       Contact contact = database.getContact(senderId); 
       if(senderId.equals(localUserId)){  //True if the local user sent this message 
        senderFirstName = "Me"; 
       } 
       else{ 
        senderFirstName = contact.getFirstName(); 
       } 
       userImage.setImageBitmap(contact.getImageBitmap(100, 100, 6)); 
       messageHeading.setText(senderFirstName); 
      } 

      messageBody = (TextView) view.findViewById(R.id.activity_view_conversation_message_list_item_contents); 
      messageBody.setText(message.getContents(null)); 

      break;    
     case Message.MESSAGE_TYPE_IMAGE:   //Image message 
      view = vi.inflate(R.layout.activity_view_conversation_message_list_item_image, null);  //Inflate a list item template for displaying an image 
      userImage = (ImageView) view.findViewById(R.id.activity_view_conversation_message_list_item_user_image); 

      //Sender's first name 
      messageHeading = (TextView) view.findViewById(R.id.activity_view_conversation_message_list_item_heading); 
      Contact contact = database.getContact(senderId); 
      if(senderId.equals(localUserId)){  //True if the local user sent this message 
       senderFirstName = "Me"; 
      } 
      else{ 
       senderFirstName = contact.getFirstName(); 
      } 
      messageHeading.setText(senderFirstName); 
      messageImage = (ImageView) view.findViewById(R.id.activity_view_conversation_message_list_item_image); 
      String imageResourceId = null; 
      //The message is a JSON object containing several fields, one of which is the file name which we will use to get the image 
      try { 
       JSONObject messageJSON = new JSONObject(message.getContents(null)); 
       String imagePath = Environment.getExternalStorageDirectory()+"/epicChat/resources/"+messageJSON.getString("fileName"); 
       int imageWidth = messageJSON.getInt("width");  //We want the dimensions in order to calculate the aspect ratio of the image 
       int imageHeight = messageJSON.getInt("height"); 
       if(messageJSON.has("resourceId")){ 
        imageResourceId = messageJSON.getString("resourceId"); //This is used when opening the image gallery 
       } 
       int displayWidth = 300; 
       int displayHeight = (int) ((float) imageHeight/(float) imageWidth * (float) displayWidth); 
       String imagePathFull = imagePath+displayWidth+displayHeight;   //For the caching 
       Bitmap originalImage = null; 
       //Check the bitmap cache exists. If not, reinstantiate it 
       if(MainActivity.bitmapCache==null){     //Cache is null 
        MainActivity.loadBitmapCache(); 
       } 
       else{            //Cache is not null, so check it to see if this image is in it 
        originalImage = MainActivity.bitmapCache.get(imagePathFull); 
       } 
       if(originalImage==null){  //True if the bitmap was not in the cache. So we must load from disk instead 
        new Utils.LoadBitmapAsync(imagePath, messageImage, displayWidth, displayHeight, MainActivity.bitmapCache).execute(); 
        messageImage.getLayoutParams().height = displayHeight; 
       } 
       else{ 
        messageImage.setImageBitmap(originalImage); 
       } 
      } 
      catch (JSONException e) { 
       Log.e(TAG, "Error reading image JSON: "+e.toString()); 
      } 
      if(imageResourceId!=null){  //Only attach the listener if we got a valid resource ID 
       final String recourceIdFinal = imageResourceId; 
       final String conversationIdFinal = message.getUserList(); 
       messageImage.setOnClickListener(new OnClickListener() { 
        @Override 
        public void onClick(View v) { 
         Intent showConversationImageGalleryIntent = new Intent(context, ViewConversationImageGalleryActivity.class); 
         showConversationImageGalleryIntent.putExtra("conversationId", conversationIdFinal); 
         showConversationImageGalleryIntent.putExtra("resourceId", recourceIdFinal); 
         startActivityForResult(showConversationImageGalleryIntent, ACTION_SHOW_CONVERSATION_IMAGE_GALLERY); 
        } 
       }); 
      } 
      userImage.setImageBitmap(contact.getImageBitmap(100, 100, 6)); 
      break; 
     case Message.MESSAGE_TYPE_INVALID: 
     default: 
      break; 
     } 

     //Some layout items are present in all layouts. Typically these are the status indicator and the message time 
     RelativeLayout itemLayout = (RelativeLayout) view.findViewById(R.id.activity_view_conversation_message_list_item_wrapper); 
     //If the message is from the local user, give it a subtle grey background 
     if(localUserId.equals(message.getFromUser())){ 
      itemLayout.setBackgroundColor(Color.parseColor("#E9E9E9")); 
     } 
     else{ 
      itemLayout.setBackgroundColor(Color.parseColor("#FFFFFF")); 
     } 
     TextView messageTimeText = (TextView) view.findViewById(R.id.activity_view_conversation_message_list_item_time); 
     messageTimeText.setText(message.getFormattedTime()); 

     ImageView messageStatusImage = (ImageView) view.findViewById(R.id.activity_view_conversation_message_list_item_ack); 
     //Set the status image according to the status of the message 
     switch(message.getStatus()){ 
     case Message.MESSAGE_STATUS_PENDING:  //Pending messages should have a red dot 
      messageStatusImage.setImageResource(R.drawable.red_dot_8dp); 
      messageStatusImage.setVisibility(View.VISIBLE); 
      break; 
     case Message.MESSAGE_STATUS_ACK_SERVER:  //Messages that reached the server should have an orange dot 
      messageStatusImage.setImageResource(R.drawable.orange_dot_8dp); 
      messageStatusImage.setVisibility(View.VISIBLE); 
      break; 
     case Message.MESSAGE_STATUS_ACK_RECIPIENT: //Messages that reached the recipient should have an green dot 
      messageStatusImage.setImageResource(R.drawable.green_dot_8dp); 
      messageStatusImage.setVisibility(View.VISIBLE); 
      break; 
     case Message.MESSAGE_STATUS_NOT_SET:  //Not set typically means the message came from another user, in which case the status image should be hidden 
     default:         //Also default here 
      messageStatusImage.setVisibility(View.INVISIBLE); 
      break; 
     }   
     return view; 
    } 
} 
+0

Вы должны размещать код для своей реализации BaseAdapter – chopchop

+0

Добавлен код для адаптера – Tom

ответ

1

Поскольку нет другого заявления, удовлетворяющего заданных критериев, если это, вероятно, из-за просмотр рециркуляции. Когда элемент из списка ListView прокручивается с экрана, операционная система удаляет его и передает обратно на адаптер в том же состоянии, в котором оно было удалено. Это означает, что вам нужно установить цвет фона, если это не сообщение локального пользователя.

+0

Это решило его, однако, похоже, я не понимаю, как правильно обрабатывать вид. Проблема, которую я показываю на двух снимках экрана, происходит даже тогда, когда рассматриваемое представление не выходит из экрана, поэтому его нельзя перерабатывать, если это так? Я вижу, как он меняет цвет, когда я перетаскиваю его, и он все время остается в видимой области. Мне кажется, это очень странный побочный эффект переработки. – Tom

+0

Первое, что вы внедрили, метод getView сделает ваше приложение очень медленным, потому что вы каждый раз вызываете findViewById. Вы не должны этого делать. всякий раз, когда вы прокручиваете список, он вызывает метод onDraw, который перерисовывает ваш список. поэтому, если вы не ставите иначе условие фона этой строки будет серым. – Ankit

+0

Я читал на getView, и мне кажется, что я должен использовать метод id элемента, чтобы позволить мне перерабатывать представления. Но ни один из ответов здесь не объясняет, почему цвет фона элемента списка постепенно изменяется от белого к серому.Я мог понять, вдруг ли это изменилось, но это плавное изменение: от FFFFFF до DDDDDD, где элемент FFFFFF, если он находится в верхней части контейнера, но по мере его перемещения он медленно изменяется на DDDDDD. Что-то еще должно происходить здесь, поскольку цвет интерполируется в зависимости от того, насколько далеко по странице находится элемент. Мне просто интересно – Tom

Смежные вопросы