非常に奇妙な ListView の動作に遭遇しています。ListView と BaseAdapter のカスタム実装を使用してメッセージを表示する単純なチャット アプリケーションがあります。
私が考えていたのは、「ローカル」ユーザーからのメッセージをグレーで覆い、「リモート」ユーザーからのメッセージを白くして、ユーザーが 2 つを区別できるようにすることでした。以下の 2 つのスクリーンショットは、何が起こっているかを示しています。2 つ目はまったく同じアクティビティ (xml など) で、少し下にスクロールしただけです。
上にスクロール:
下にスクロール:
"Me" @ 23:05 から送信されたメッセージを見てください。一番上にあるときは隣とのコントラストはありませんが、一番下までスクロールすると違いがはっきりとわかります。これは、4.2.2 上の nexus 4 および 7、および 4.1.2 を実行している GS3 で発生します。
ListView 項目の 1 つの 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>
ここで、RelativeLayout の色を設定します。
if(localUserId.equals(remoteUserId)){
itemLayout.setBackgroundColor(Color.parseColor("#F9F9F9"));
}
そのコードは、アダプターの getView() メソッド内で実行されます。
私はこれをかなりグーグルで検索しましたが、何も見つかりませんでした.android:cacheColorHintの問題に関して多くの質問がありますが、それがここで起こっているとは思いません.
誰もこれに遭遇したことがありますか?私は困惑しています!
編集: 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;
}
}