Issues with rendering in Android ListView in Visual Studio Xamarin

AdeptusAdeptus TRMember ✭✭
edited July 2017 in Xamarin.Android

Hello to all programmers. I try to create simple chat. The first chatter's messages should be in white square with rounded corners, the second chatter's messages should be in blue square with rounded corners and with some icon. So I decided to use listview and adapter for this task. In adapter I use simple set of data {bool type, sting message, DateTime date}. So Adapter Code is

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);
    }
}

In Activity I fill Adapter with test information that way - message from 1-st chatter, message from 2-nd chatter. It repeats 10 times.
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;
    }
}

When I run app (in Visual studio emulator for android) first rendering of list is correct, but when I scroll list up/down, the layouts of ListView mixes - 1-st chatter's message sometimes get 2-nd chatter's template (with blue square and icon), 2-nd chatter's message sometimes get 1-st chatter's template (with white square and no icon).
For Example
Example
Can anybody help me with this issue? Any help will be appreciated.

Best Answer

  • AdeptusAdeptus TR ✭✭
    Accepted Answer

    At least I found the solution
    As suggest Iulian Popescu according answer for this post solution for this issue is using two different ViewHolder and implementing GetItemViewType adapter's method . In my case that is ChatUserMessagesViewHolder for 1-st chatter's messages and ChatWorkerMessagesViewHolder for 2-nd chatter's messages.
    The code of solution is
    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 _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);
        }
    }
    

Answers

  • cwphillicwphilli USMember ✭✭✭

    Where is the Initialize code?
    It sounds as if you are conditionally setting the view to one or the either's layout, but instead you need to set the layout elements to the desired output every time. If you don't, view's are re-used/recycled, hence what you're experiencing.

  • AdeptusAdeptus TRMember ✭✭

    To @cwphilli Sorry, I don't understand - Initialize what?

  • AdeptusAdeptus TRMember ✭✭
    Accepted Answer

    At least I found the solution
    As suggest Iulian Popescu according answer for this post solution for this issue is using two different ViewHolder and implementing GetItemViewType adapter's method . In my case that is ChatUserMessagesViewHolder for 1-st chatter's messages and ChatWorkerMessagesViewHolder for 2-nd chatter's messages.
    The code of solution is
    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 _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);
        }
    }
    
  • cwphillicwphilli USMember ✭✭✭
    edited July 2017

    I was asking about the implementation of this from your code:
    public void initialize(View view){}

    However the below working code that you found illustrates what I was explaining to you ;)
    You need to set the view's each and every time in GetView for it to work properly.

    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;
            }
    
Sign In or Register to comment.