Reputation: 4222
I'm having some issues with my custom ArrayAdapter. I'm trying to build a view based on certain properties, however as soon as I start scrolling (and sometimes even before that), the views aren't build correctly and are shown incorrect. I know this has something to do with the fact that a ListView reuses items, but I can't figure out how to solve it. In theory this code should work.. At least that is what I'm thinking.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
rowView = inflater.inflate(R.layout.message_view_row, null);
image = (ImageView) rowView.findViewById(R.id.message_row_image);
messageText = (TextView) rowView
.findViewById(R.id.message_row_message);
senderName = (TextView) rowView
.findViewById(R.id.message_row_senderName);
dateText = (TextView) rowView.findViewById(R.id.message_row_date);
mainLayout = (LinearLayout) rowView
.findViewById(R.id.messaging_view_mainLayout);
messageLayout = (LinearLayout) rowView
.findViewById(R.id.message_row_messageLayout);
} else {
image = (ImageView) rowView.findViewById(R.id.message_row_image);
messageText = (TextView) rowView
.findViewById(R.id.message_row_message);
senderName = (TextView) rowView
.findViewById(R.id.message_row_senderName);
dateText = (TextView) rowView.findViewById(R.id.message_row_date);
mainLayout = (LinearLayout) rowView
.findViewById(R.id.messaging_view_mainLayout);
messageLayout = (LinearLayout) rowView
.findViewById(R.id.message_row_messageLayout);
}
Message msg = messages.get(position);
View imageFromMain = mainLayout.getChildAt(0);
View messageLayoutFromMain = mainLayout.getChildAt(1);
mainLayout.removeAllViews();
// handle the view stance
if (!msg.isOwnMessage()) {
// switch the views
mainLayout.addView(messageLayoutFromMain);
mainLayout.addView(imageFromMain);
// set the color for the message box
messageLayout.setBackgroundColor(context.getResources().getColor(
R.color.friend_message_color));
} else {
// switch the views
mainLayout.addView(imageFromMain);
mainLayout.addView(messageLayoutFromMain);
messageLayout.setBackgroundColor(context.getResources().getColor(
R.color.clanster_color));
}
messageText.setText(msg.getMessage());
senderName.setText(msg.getSenderName());
Date date = msg.getCreatedAt();
dateText.setText(dateFormat.format(msg.getCreatedAt()));
if (msg.getSenderImageUrl() != null
&& !msg.getSenderImageUrl().isEmpty()) {
Picasso.with(context).load(msg.getSenderImageUrl())
.transform(new RoundedTransformation()).into(image);
} else {
Picasso.with(context).load(R.drawable.defaultimage)
.transform(new RoundedTransformation()).into(image);
}
return rowView;
}
This part where it isn't working is the part where I remove all views from a layout and re-add them in a certain order based on a certain property.
Upvotes: 1
Views: 56
Reputation: 8680
This is a better way to handle your issue:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.message_view_row, null);
}
image = (ImageView) convertView.findViewById(R.id.message_row_image);
messageText = (TextView) convertView.findViewById(R.id.message_row_message);
senderName = (TextView) convertView.findViewById(R.id.message_row_senderName);
dateText = (TextView) convertView.findViewById(R.id.message_row_date);
mainLayout = (LinearLayout) convertView.findViewById(R.id.messaging_view_mainLayout);
messageLayout = (LinearLayout) convertView.findViewById(R.id.message_row_messageLayout);
Message msg = messages.get(position);
//your problem area is here:
//**View imageFromMain = mainLayout.getChildAt(0);**
//**View messageLayoutFromMain = mainLayout.getChildAt(1);**
//when the view is recycled, you cannot assume
//that the views will be at the needed positions. instead, you should refactor
//your code to make them separate views, and inflate them like this
View imageFormMain = inflater.inflate(<your_refactored_view_name1>);
View messageLayoutFromMain = inflater.inflate(<your_refactored_view_name2>);
mainLayout.removeAllViews();
// handle the view stance
if (!msg.isOwnMessage()) {
// switch the views
mainLayout.addView(messageLayoutFromMain);
mainLayout.addView(imageFromMain);
// set the color for the message box
messageLayout.setBackgroundColor(context.getResources().getColor(
R.color.friend_message_color));
} else {
// switch the views
mainLayout.addView(imageFromMain);
mainLayout.addView(messageLayoutFromMain);
messageLayout.setBackgroundColor(context.getResources().getColor(
R.color.clanster_color));
}
messageText.setText(msg.getMessage());
senderName.setText(msg.getSenderName());
Date date = msg.getCreatedAt();
dateText.setText(dateFormat.format(msg.getCreatedAt()));
if (msg.getSenderImageUrl() != null && !msg.getSenderImageUrl().isEmpty()) {
Picasso.with(context).load(msg.getSenderImageUrl())
.transform(new RoundedTransformation()).into(image);
} else {
Picasso.with(context).load(R.drawable.defaultimage)
.transform(new RoundedTransformation()).into(image);
}
return convertView;
}
Upvotes: 1
Reputation: 2771
Change the first part of your getView()
to this. You are rewriting the code twice, it's not necessary and it looks messy.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mInflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = mInflator.inflate(R.layout.message_view_row, parent, null);
}
image = (ImageView) convertView.findViewById(R.id.message_row_image);
messageText = (TextView) convertView
.findViewById(R.id.message_row_message);
senderName = (TextView) convertView
.findViewById(R.id.message_row_senderName);
dateText = (TextView) convertView.findViewById(R.id.message_row_date);
mainLayout = (LinearLayout) rowView
.findViewById(R.id.messaging_view_mainLayout);
messageLayout = (LinearLayout) convertView
.findViewById(R.id.message_row_messageLayout);
...
return convertView;
Notice when you are inflating your convertView to pass parent as a parameter
Upvotes: 0
Reputation: 855
Try this:
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(layout, parent, false);
Instead of:
View rowView = convertView;
Hope this helps.
Upvotes: 0