[英]ListView item background changes depending on scroll position
I'm running into a very strange ListView behaviour. 我遇到了一个非常奇怪的ListView行为。 I have a simple chat application which uses a ListView and a custom implementation of BaseAdapter to show messages. 我有一个简单的聊天应用程序,它使用ListView和BaseAdapter的自定义实现来显示消息。
The idea I had was to shade messages from the "local" user grey and have messages from the "remote" user white, to help the user distinguish between the two. 我当时的想法是将“本地”用户的邮件涂成灰色,将“远程”用户的邮件涂成白色,以帮助用户区分两者。 The two screenshots below show what's happening. 下面的两个屏幕截图显示了正在发生的事情。 The second is the exact same activity, xml etc etc, simply scrolled down a bit. 第二个是完全相同的活动,xml等,只需向下滚动一下即可。
Scrolled up: 向上滚动:
Scrolled down: 向下滚动:
Look at the message sent by "Me" @ 23:05. 查看“我” @ 23:05发送的消息。 When at the top it has no contrast to its neighbours, but when it is scrolled to the bottom, the difference is clear to see. 当位于顶部时,它与周围没有任何对比,但是当滚动到底部时,很明显可以看到区别。 This occurs on a nexus 4 and 7 on 4.2.2, and a GS3 running 4.1.2. 这发生在4.2.2的联系4和7,以及运行4.1.2的GS3上。
Here is the XML for one of the ListView items: 这是ListView项之一的XML:
<?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>
And here is where I set the colour of the RelativeLayout: 这是我设置RelativeLayout的颜色的地方:
if(localUserId.equals(remoteUserId)){
itemLayout.setBackgroundColor(Color.parseColor("#F9F9F9"));
}
That code runs inside the getView() method of my Adapter. 该代码在我的适配器的getView()方法中运行。
I've Googled this a fair bit and turned up nothing, there are a lot of SO questions regarding the android:cacheColorHint issue but I don't think that is what is going on here. 我已经用Google搜索了一下,什么也没发现,关于android:cacheColorHint问题有很多SO问题,但是我不认为这是怎么回事。
Has anyone run into this before? 有人遇到过吗? I'm stumped! 我很沮丧!
EDIT: Here's the baseadapter code: 编辑:这是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;
}
}
Since there's no else statement matching your if, this is probably due to view recycling. 由于没有其他与您的if匹配的语句,这可能是由于视图回收所致。 When an item from a ListView scrolls off the screen, the operating system removes it and hands it back to the adapter in the same state it was removed. 当ListView中的项目从屏幕上滚动时,操作系统将其删除,并以与删除状态相同的状态将其交还给适配器。 This means you need to set the background color when it's not the local user's message as well. 这意味着您还需要设置背景颜色,而不是本地用户的消息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.