具有多个布局的 ListView - 如何将每一行保持在给定的布局中

Posted

技术标签:

【中文标题】具有多个布局的 ListView - 如何将每一行保持在给定的布局中【英文标题】:ListView with multiple layouts - how to keep each row in a given layout 【发布时间】:2021-05-11 10:41:51 【问题描述】:

我有以下布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_>

    <TextView
        android:layout_
        android:layout_
        android:id="@+id/textGoesHere"
        android:drawableRight="@drawable/row_receive"
        android:text="hello alert" />

</RelativeLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_
    android:layout_>

    <TextView
        android:layout_
        android:layout_
        android:id="@+id/textGoesHere"
        android:drawableLeft="@drawable/row_send"
        android:text="hello alert" />

</LinearLayout>

我正在尝试创建一个显示这两种布局的 ListView。这是我的 java 代码,它具有主类、一个 Message 类,它存储用户填写的 EditText 中的数据,并且应该填充 ListView,最后是自定义 Adapter 类:

package com.example.androidlabs;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class ChatRoomActivity extends AppCompatActivity 

    List<String> listElements = new ArrayList<String>();
    ListView theListView;
    Button sendButton;
    Button receiveButton;
    EditText chatText;
    Adapter adapter;
    Message message = new Message();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat_room);

        theListView = (ListView) findViewById(R.id.theListView);
        sendButton = (Button) findViewById(R.id.sendButton);
        chatText = (EditText) findViewById(R.id.chatText);
        receiveButton = (Button) findViewById(R.id.receiveButton);

        theListView.setAdapter(adapter = new Adapter());

       // sendButton.setOnClickListener(click -> listElements.add("new element"));
       sendButton.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v)  
                message.setMessage(chatText.getText().toString());
                message.setType(0);
                listElements.add(chatText.getText().toString());
                adapter.notifyDataSetChanged();
            
        );

        receiveButton.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v)  
                message.setMessage(chatText.getText().toString());
                message.setType(1);
                listElements.add(chatText.getText().toString());
                adapter.notifyDataSetChanged();
            
        );
    

    public class Message 
        private String text;
        private int type;

        public void setMessage(String text)  this.text = text; 
        public String getMessage()   return text; 

        public void setType(int type)   this.type = type; 
        public int getType()  return type; 
        

    public class Adapter extends BaseAdapter 

        @Override
        public int getViewTypeCount()  
            return 2;
        

        @Override
        public int getItemViewType(int position)  
            if (message.getType() == 0)  return 0; 
            else  return 1; 
        
        @Override
        public int getCount() 
            return listElements.size();
        

        @Override
        public Object getItem(int position) 
            return listElements.get(position);
        

        @Override
        public long getItemId(int position) 
            return (long) position;
        

        @Override
        public View getView(int position, View old, ViewGroup parent) 

            View newView = old;
            LayoutInflater inflater = getLayoutInflater();
            int listViewItemType = this.getItemViewType(position);

            //make a new row
            if (newView == null)  

                if (listViewItemType == 0) 
                    newView = inflater.inflate(R.layout.row_send_layout, parent, false);
                
                else  
                    newView = inflater.inflate(R.layout.row_receive_layout, parent, false);
                

            

            //set what the text should be for this row:
            TextView tView = newView.findViewById(R.id.textGoesHere);
            tView.setText( getItem(position).toString() );

            //return it to be put in the table
            return newView;
        
    

我希望列表视图如下所示:

The ListView I want

但最终发生的是它会根据用户单击的按钮更改 ListView 的所有布局:

The ListView I get if I click on "Send"

The ListView I get if I click on "Recieve"

我可以在我的代码中进行哪些调整以获得预期的结果?我假设它在我的 getView() 方法中,但我不知道那是什么。

【问题讨论】:

列表视图已弃用,您应该考虑学习回收者视图 【参考方案1】:

您经常使用相同的引用 Message:Message message = new Message();

因此,当发送新消息时,它也会完全覆盖旧消息。您通过将文本存储在上面的 ArrayList 中保存了文本,因此当布局刷新时,它只是从那里加载文本,但消息类型是从单个消息中一遍又一遍地读取...

要修复它,您还需要将消息放在 Array/ArrayList 中。这样做时,我还会删除listElements-Arraylist,因为它只存储消息本身也存储的相同消息...存储相同的数据两次是一种不好的做法,因为这可能会导致更改时出现问题只有其中之一。

因此,不要在onClickListeners 中调用setMessagesetType 方法,而是创建Message 的新实例,用数据填充它并将其存储在ArrayList 中。然后,在适配器的getViewgetItemViewType函数中,从传入的position参数中获取所需的消息。

【讨论】:

以上是关于具有多个布局的 ListView - 如何将每一行保持在给定的布局中的主要内容,如果未能解决你的问题,请参考以下文章

具有不同布局的 ListView 行

具有多种布局的Android ListView

每行具有不同布局的Android ListView

具有流式布局的 UICollectionView 不会将多个项目放在一行上

ListView: setvisibility() 强制刷新所有行

如何使listView中的一行始终具有相同的颜色android