欢迎所有程序员。我尝试创建简单的聊天。第一个聊天的消息应该是带有圆角的白色方块,第二个聊天消息应该是带有圆角的蓝色方块和一些图标。所以我决定使用listview和adapter来完成这项任务。在适配器中我使用简单的数据集{bool type,sting message,DateTime date}。所以适配器代码是
class ChatMessagesViewHolder : Java.Lang.Object
{
internal TextView chatMessageView;
public void initialize(View view){}
}
public class ChatMessagesAdapter : BaseAdapter
{
Activity _context;
List<MessageData> _dataList;
public ChatMessagesAdapter(Activity context, List<MessageData> dataList)
{
_context = context;
_dataList = dataList;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
ChatMessagesViewHolder chatMessagesViewHolderClass;
View view;
view = convertView;
int layout = _dataList[position]._type == 0 ? Resource.Layout.MessageLitsUserItem:Resource.Layout.MessageListWorkerItem;
Typeface openSansRegular = Typeface.CreateFromAsset(_context.Assets, "fonts/OpenSans-Regular.ttf");
if (view == null)
{
view = _context.LayoutInflater.Inflate(layout, parent, false);
chatMessagesViewHolderClass = new ChatMessagesViewHolder();
chatMessagesViewHolderClass.chatMessageView = view.FindViewById<TextView>(Resource.Id.messageText);
chatMessagesViewHolderClass.initialize(view);
view.Tag = chatMessagesViewHolderClass;
}
else
{
chatMessagesViewHolderClass = (ChatMessagesViewHolder)view.Tag;
}
chatMessagesViewHolderClass.chatMessageView.Typeface = openSansRegular;
chatMessagesViewHolderClass.chatMessageView.Text = _dataList[position]._date.ToString()+"\n"+ _dataList[position]._message;
return view;
}
public void Add(MessageData messageData)
{
_dataList.Add(messageData);
}
}
在Activity中,我用适当的方式填充适配器测试信息 - 来自第一个聊天的消息,来自第二个聊天的消息。它重复了10次。
public class ChatActivity : Activity{
ListView chatList;
ChatMessagesAdapter chatAdapter;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ChatLayout);
List<MessageData> dataList = new List<MessageData>();
for (int i = 0; i < 20; i++)
{
string message = "Test message from chatter "+(i%2).ToString();
dataList.Add(new MessageData(i % 2, message, DateTime.Now));
}
chatAdapter = new ChatMessagesAdapter(this, dataList);
chatList.Adapter = chatAdapter;
}
}
当我运行app(在Visual Studio模拟器中为android)时,首先渲染列表是正确的,但是当我向上/向下滚动列表时,ListView混合的布局 - 第一个聊天消息有时会得到第二个聊天模板(蓝色方块和图标),第二个聊天的消息有时会得到第一个聊天模板(白色方块,没有图标)。 例如
有人可以帮我解决这个问题吗?任何帮助将不胜感激。
已更新
适配器的新代码,已更新为与不同类型的消息使用两个不同的ViewHolder。
class ChatUserMessagesViewHolder : Java.Lang.Object
{
internal RelativeLayout messageBox;
internal TextView messageText;
public void initialize(View view) { }
}
class ChatWorkerMessagesViewHolder : Java.Lang.Object
{
internal RelativeLayout messageBox;
internal TextView messageText;
internal ImageView workerIcon;
public void initialize(View view) { }
}
public class ChatMessagesAdapter : BaseAdapter
{
Activity _context;
List<MessageData> _dataList;
public ChatMessagesAdapter(Activity context, List<MessageData> dataList)
{
_context = context;
_dataList = dataList;
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return position;
}
public override int Count
{
get
{
return _dataList.Count;
}
}
public override int GetItemViewType(int position)
{
return _dataList[position]._type;
}
public override int ViewTypeCount
{
get
{
return 2;
}
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
ChatMessagesViewHolder chatMessagesViewHolderClass;
ChatWorkerMessagesViewHolder chatWorkerMessagesViewHolderClass;
ChatUserMessagesViewHolder chatUserMessagesViewHolderClass;
View view;
view = convertView;
int layout = _dataList[position]._type == 0 ? Resource.Layout.MessageLitsUserItem:Resource.Layout.MessageListWorkerItem;
Typeface openSansRegular = Typeface.CreateFromAsset(_context.Assets, "fonts/OpenSans-Regular.ttf");
if (view == null)
{
switch (GetItemViewType(position))
{
case 0:
view = _context.LayoutInflater.Inflate(Resource.Layout.MessageLitsUserItem, null);
chatUserMessagesViewHolderClass = new ChatUserMessagesViewHolder();
chatUserMessagesViewHolderClass.messageBox = view.FindViewById<RelativeLayout>(Resource.Id.messageBox);
chatUserMessagesViewHolderClass.messageText = view.FindViewById<TextView>(Resource.Id.messageText);
chatUserMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatUserMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
view.Tag = chatUserMessagesViewHolderClass;
break;
case 1:
view = _context.LayoutInflater.Inflate(Resource.Layout.MessageListWorkerItem, null);
chatWorkerMessagesViewHolderClass = new ChatWorkerMessagesViewHolder();
chatWorkerMessagesViewHolderClass.messageBox = view.FindViewById<RelativeLayout>(Resource.Id.messageBox);
chatWorkerMessagesViewHolderClass.messageText = view.FindViewById<TextView>(Resource.Id.messageText);
chatWorkerMessagesViewHolderClass.workerIcon = view.FindViewById<ImageView>(Resource.Id.workerIcon);
chatWorkerMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatWorkerMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
break;
}
}
else
{
switch (GetItemViewType(position))
{
case 0:
chatUserMessagesViewHolderClass = (ChatUserMessagesViewHolder)view.Tag;
chatUserMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatUserMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
break;
case 1:
chatWorkerMessagesViewHolderClass = (ChatWorkerMessagesViewHolder)view.Tag;
chatWorkerMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatWorkerMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
break;
}
}
return view;
}
public void Add(MessageData messageData)
{
_dataList.Add(messageData);
}
}
答案 0 :(得分:1)
建议 Iulian Popescu 根据 answer for this post 解决此问题的方法是使用两个不同的 ViewHolder 并实施 GetItemViewType 适配器的方法。在我的情况下,对于第一个聊天消息是 ChatUserMessagesViewHolder ,对于第二个聊天消息是 ChatWorkerMessagesViewHolder 。 解决方案的代码是
class ChatUserMessagesViewHolder : Java.Lang.Object
{
internal RelativeLayout messageBox;
internal TextView messageText;
public void initialize(View view) { }
}
class ChatWorkerMessagesViewHolder : Java.Lang.Object
{
internal RelativeLayout messageBox;
internal TextView messageText;
internal ImageView workerIcon;
public void initialize(View view) { }
}
public class ChatMessagesAdapter : BaseAdapter
{
Activity _context;
List<MessageData> _dataList;
public ChatMessagesAdapter(Activity context, List<MessageData> dataList)
{
_context = context;
_dataList = dataList;
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return position;
}
public override int Count
{
get
{
return _dataList.Count;
}
}
public override int GetItemViewType(int position)
{
return _dataList[position]._type;
}
public override int ViewTypeCount
{
get
{
return 2;
}
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
ChatWorkerMessagesViewHolder chatWorkerMessagesViewHolderClass;
ChatUserMessagesViewHolder chatUserMessagesViewHolderClass;
View view;
view = convertView;
int layout = _dataList[position]._type == 0 ? Resource.Layout.MessageLitsUserItem : Resource.Layout.MessageListWorkerItem;
Typeface openSansRegular = Typeface.CreateFromAsset(_context.Assets, "fonts/OpenSans-Regular.ttf");
if (view == null)
{
switch (GetItemViewType(position))
{
case 0:
view = _context.LayoutInflater.Inflate(Resource.Layout.MessageLitsUserItem, null);
chatUserMessagesViewHolderClass = new ChatUserMessagesViewHolder();
chatUserMessagesViewHolderClass.messageBox = view.FindViewById<RelativeLayout>(Resource.Id.messageBox);
chatUserMessagesViewHolderClass.messageText = view.FindViewById<TextView>(Resource.Id.messageText);
chatUserMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatUserMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
view.Tag = chatUserMessagesViewHolderClass;
break;
case 1:
view = _context.LayoutInflater.Inflate(Resource.Layout.MessageListWorkerItem, null);
chatWorkerMessagesViewHolderClass = new ChatWorkerMessagesViewHolder();
chatWorkerMessagesViewHolderClass.messageBox = view.FindViewById<RelativeLayout>(Resource.Id.messageBox);
chatWorkerMessagesViewHolderClass.messageText = view.FindViewById<TextView>(Resource.Id.messageText);
chatWorkerMessagesViewHolderClass.workerIcon = view.FindViewById<ImageView>(Resource.Id.workerIcon);
chatWorkerMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatWorkerMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
view.Tag = chatWorkerMessagesViewHolderClass;
break;
}
}
else
{
switch (GetItemViewType(position))
{
case 0:
chatUserMessagesViewHolderClass = (ChatUserMessagesViewHolder)view.Tag;
chatUserMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatUserMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
break;
case 1:
chatWorkerMessagesViewHolderClass = (ChatWorkerMessagesViewHolder)view.Tag;
chatWorkerMessagesViewHolderClass.messageText.Typeface = openSansRegular;
chatWorkerMessagesViewHolderClass.messageText.Text = _dataList[position]._date.ToString() + "\n" + _dataList[position]._message;
break;
}
}
return view;
}
public void Add(MessageData messageData)
{
_dataList.Add(messageData);
}
}
答案 1 :(得分:0)
这种行为的发生是因为一种名为view recycling的机制,它基本上重用了现有的列表视图项,如果它不再可见(这通常发生在它滚动到屏幕之外时,因此只有在滚动时才会出现这种情况)是的。)
chatMessagesViewHolderClass.chatMessageView.Typeface = openSansRegular;
chatMessagesViewHolderClass.chatMessageView.Text = _dataList[position]._date.ToString()+"\n"+ _dataList[position]._message;
在上面的代码中,您为列表设置了数据,但是您完全忽略了应该如何生成行。
要解决您必须在适配器getItemViewType
中实现的问题,以便让它知道您有多个布局。我无法帮助您处理任何C#
代码,但here您可以找到如何在Java
中使用该代码的示例。