在Visual Studio Xamarin中使用Android ListView进行渲染的问题

时间:2017-07-06 07:11:47

标签: android visual-studio listview

欢迎所有程序员。我尝试创建简单的聊天。第一个聊天的消息应该是带有圆角的白色方块,第二个聊天消息应该是带有圆角的蓝色方块和一些图标。所以我决定使用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混合的布局 - 第一个聊天消息有时会得到第二个聊天模板(蓝色方块和图标),第二个聊天的消息有时会得到第一个聊天模板(白色方块,没有图标)。 例如

Example

有人可以帮我解决这个问题吗?任何帮助将不胜感激。

已更新

适配器的新代码,已更新为与不同类型的消息使用两个不同的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);
    }
}

2 个答案:

答案 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中使用该代码的示例。