【问题标题】:How to programmatically add CardView to LinearLayout in a RecyclerView如何以编程方式将 CardView 添加到 RecyclerView 中的 LinearLayout
【发布时间】:2018-10-14 14:54:49
【问题描述】:

是否可以在RecyclerView 内以编程方式将CardView 添加到LinearLayout。目前,所有CardViews 都添加到RecyclerView,但我希望将屏幕截图中的那些添加到LinearLayout

片段类

public class TabFragmentRV extends android.support.v4.app.Fragment {
    RecyclerView mRecyclerView;

    public TabFragmentRV() {}

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_rv, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        View v = getView();
        assert v != null;

        mRecyclerView = v.findViewById(R.id.my_recyclerview);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));

        super.onActivityCreated(savedInstanceState);

        initRVAdapter();
    }

    private void initRVAdapter(){
        List<Object> itemsList = new ArrayList<>();

        RVItemsAapter itemsListAdapter = new RVItemsAapter(getContext());
        mRecyclerView.setAdapter(itemsListAdapter);

        itemsList.add(new RVLineSeparator());
        itemsList.add(new SectionHeader("Section E"));
        itemsList.add(new SMSmessage("Item E1","Item E1 description"));
        itemsList.add(new SMSmessage("Item E2","Item E2 description"));
        itemsList.add(new SMSmessage("Item E3","Item E3 description"));
        itemsList.add(new SMSmessage("Item E4","Item E4 description"));
        itemsList.add(new RVLineSeparator());

        itemsListAdapter.setCallSMSFeed(itemsList);
        itemsListAdapter.notifyDataSetChanged();
    }
}

适配器类

public class RVItemsAapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private final static int TYPE_MAINHEADER = 1, TYPE_EXPANDABLE = 2, TYPE_NONEXPANDABLE = 3, TYPE_SECTIONHEADER = 4, TYPE_TABLE = 5, TYPE_SEPARATOR = 6;
    private ArrayList callSMSFeed = new ArrayList();

    private Context context;


    public RVItemsAapter(Context context){this.context=context;}

    public void setCallSMSFeed(List<Object> callSMSFeed){
        this.callSMSFeed = (ArrayList) callSMSFeed;
    }

    @Override
    public int getItemViewType(int position) {
        if (callSMSFeed.get(position) instanceof MainHeader) {
            return TYPE_MAINHEADER;
        } else if (callSMSFeed.get(position) instanceof Phonecall) {
            return TYPE_EXPANDABLE;
        } else if (callSMSFeed.get(position) instanceof SMSmessage) {
            return TYPE_NONEXPANDABLE;
        } else if (callSMSFeed.get(position) instanceof SectionHeader) {
            return TYPE_SECTIONHEADER;
        } else if (callSMSFeed.get(position) instanceof MyTable) {
            return TYPE_TABLE;
        } else if (callSMSFeed.get(position) instanceof RVLineSeparator) {
            return TYPE_SEPARATOR;
        }
        throw new IllegalArgumentException("Item at position " + position + " is not an instance of either Phonecall or SMSmessage");
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        int viewType=holder.getItemViewType();
        switch (viewType){
            case TYPE_MAINHEADER:
                MainHeader mainHeader = (MainHeader) callSMSFeed.get(position);
                ((MHeaderViewHolder)holder).showMHeaderDetails(mainHeader);
                break;
            case TYPE_EXPANDABLE:
                Phonecall call = (Phonecall) callSMSFeed.get(position);
                ((CallViewHolder)holder).showCallDetails(call);
                break;
            case TYPE_NONEXPANDABLE:
                SMSmessage sms = (SMSmessage) callSMSFeed.get(position);
                ((SMSViewHolder)holder).showSmsDetails(sms);
                break;
            case TYPE_SECTIONHEADER:
                SectionHeader sectionHeader = (SectionHeader) callSMSFeed.get(position);
                ((SectionViewHolder)holder).showSectionDetails(sectionHeader);
                break;
            case TYPE_TABLE:
                TableToilets tblToilets = (TableToilets) callSMSFeed.get(position);
                ((TblViewHolder)holder).showTblDetails(tblToilets);
                break;
            case TYPE_SEPARATOR:
                ((SeparatorViewHolder)holder).showSeparatorDetails();
                break;
            default:
                throw new IllegalArgumentException("unexpected viewType: " + viewType);
        }
    }

    @Override
    public int getItemCount(){return callSMSFeed.size();}

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {


        int layout;
        RecyclerView.ViewHolder viewHolder;
        switch (viewType){
            case TYPE_MAINHEADER:
                layout = R.layout.rv_header;
                View mainheaderView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new MHeaderViewHolder(mainheaderView);
                break;
            case TYPE_EXPANDABLE:
                layout = R.layout.cardview_dualline_withexpandability;
                View callsView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new CallViewHolder(callsView);
                break;
            case TYPE_NONEXPANDABLE:
                layout = R.layout.cardview_dualline_sansexpandability;
                View smsView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new SMSViewHolder(smsView);
                break;
            case TYPE_SECTIONHEADER:
                layout = R.layout.sectionheaderforrecyclerview;
                View sectionheaderView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new SectionViewHolder(sectionheaderView);
                break;
            case TYPE_TABLE:
                layout = R.layout.cardview_tableview_withexpandability;
                View tblView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new TblViewHolder(tblView);
                break;
            case TYPE_SEPARATOR:
                layout = R.layout.lineseparatorforrecyclerview;
                View separatorView = LayoutInflater
                        .from(parent.getContext())
                        .inflate(layout, parent, false);
                viewHolder = new SeparatorViewHolder(separatorView);
                break;
            default:
                throw new IllegalArgumentException("unexpected viewType: " + viewType);
        }
        return viewHolder;
    }

    // First ViewHolder of object type Call
    // Reference to the views for each call items to display desired information
    public class CallViewHolder extends RecyclerView.ViewHolder {
        final Typeface iconFont = FontManager.getTypeface(context, FontManager.FONTAWESOME);

        private TextView arrowexpandcollapseTextView, callerNameTextView, callTimeTextView;
        private LinearLayout llFacilityInformation;

        CallViewHolder(View itemView) {
            super(itemView);
            // Initiate view
            arrowexpandcollapseTextView = itemView.findViewById(R.id.tv_cvwithexpandability_arrowexpandcollapse);
            callerNameTextView = itemView.findViewById(R.id.tv_cvwithexpandability_title);
            callTimeTextView = itemView.findViewById(R.id.tv_cvwithexpandability_subtitle);
            llFacilityInformation = itemView.findViewById(R.id.ll_cvwithexpandability_subtitle);

            arrowexpandcollapseTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (llFacilityInformation.getVisibility() == View.GONE) {
                        expandLL(llFacilityInformation, arrowexpandcollapseTextView);
                    } else {
                        collapseLL(llFacilityInformation, arrowexpandcollapseTextView);
                    }
                }
            });

            callerNameTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (llFacilityInformation.getVisibility() == View.GONE) {
                        expandLL(llFacilityInformation, arrowexpandcollapseTextView);
                    } else {
                        collapseLL(llFacilityInformation, arrowexpandcollapseTextView);
                    }
                }
            });

            llFacilityInformation.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (llFacilityInformation.getVisibility() == View.GONE) {
                        expandLL(llFacilityInformation, arrowexpandcollapseTextView);
                    } else {
                        collapseLL(llFacilityInformation, arrowexpandcollapseTextView);
                    }
                }
            });
        }

        void showCallDetails(Phonecall call){
            // Attach values for each item
            arrowexpandcollapseTextView.setText(R.string.fa_icon_chevron_down);
            arrowexpandcollapseTextView.setTypeface(iconFont);
            llFacilityInformation.setVisibility(View.GONE);

            String callerName = call.getCallerName();
            String callTime = call.getCallTime();

            callerNameTextView.setText(callerName);
            callTimeTextView.setText(callTime);
        }
    }

    // Third ViewHolder of object type SectionHeader
    // Reference to the views for each call items to display desired information
    public class SectionViewHolder extends RecyclerView.ViewHolder {
        final Typeface iconFont = FontManager.getTypeface(context, FontManager.FONTAWESOME);

        private LinearLayout llSectionWithCards;
        private TextView arrowexpandcollapseTextView, sectionNameTextView;

        SectionViewHolder(View itemView) {
            super(itemView);
            // Initiate view
            arrowexpandcollapseTextView = itemView.findViewById(R.id.tv_sectionheaderforrv_expandcollapsearrow);
            sectionNameTextView = itemView.findViewById(R.id.tv_sectionheaderforrv_title);

            arrowexpandcollapseTextView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (llSectionWithCards.getVisibility() == View.GONE) {
                        expandLL(llSectionWithCards, arrowexpandcollapseTextView);
                    } else {
                        collapseLL(llSectionWithCards, arrowexpandcollapseTextView);
                    }
                }
            });
        }

        void showSectionDetails(SectionHeader section){
            // Attach values for each item
            arrowexpandcollapseTextView.setText(R.string.fa_icon_chevron_down);
            arrowexpandcollapseTextView.setTypeface(iconFont);

            String sectionName = section.getSectionName();

            sectionNameTextView.setText(sectionName);
        }
    }


    // Fifth ViewHolder of object type RVLineSeparator
    // Reference to the views for each call items to display desired information
    public class SeparatorViewHolder extends RecyclerView.ViewHolder {
        private View lSeparator;

        SeparatorViewHolder(View itemView) {
            super(itemView);
            lSeparator = itemView.findViewById(R.id.rv_lineseparator);
        }

        void showSeparatorDetails(){
            TypedValue tValueD = new TypedValue();
            context.getTheme().resolveAttribute(R.attr.dividerColor, tValueD, true);

            lSeparator.setBackgroundResource(tValueD.resourceId);
        }
    }

    private void expandGroup(final TextView arrowexpandcollapseTextView) {
        ?
    }

    private void collapseGroup(final TextView arrowexpandcollapseTextView) {
        ?
    }

    private void expandLL(final LinearLayout llFacilityInformation, final TextView arrowexpandcollapseTextView) {
        llFacilityInformation.setVisibility(View.VISIBLE);
        arrowexpandcollapseTextView.setText(R.string.fa_icon_chevron_up);
    }

    private void collapseLL(final LinearLayout llFacilityInformation, final TextView arrowexpandcollapseTextView) {
        llFacilityInformation.setVisibility(View.GONE);
        arrowexpandcollapseTextView.setText(R.string.fa_icon_chevron_down);
    }
}

部分标题布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_sectionwithexpandability_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ll_sectionheader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp"
        android:weightSum="100">

        <TextView
            android:id="@+id/tv_sectionheader_expandcollapsearrow"
            android:clickable="true"
            android:focusable="true"
            android:layout_weight="10"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:textColor="?android:attr/textColorPrimary"
            style="@android:style/TextAppearance.Large" />

        <TextView
            android:id="@+id/tv_sectionheader_title"
            android:layout_weight="90"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            style="@android:style/TextAppearance.Large" />
    </LinearLayout>

    <!-- I WANT ALL THE CARD VIEWS TO BE ADDED INSIDE THIS LINEARLAYOUT (ll_section_cards) -->
    <LinearLayout
        android:id="@+id/ll_section_cards"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

RecyclerView 布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout_recyclerView"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/my_recyclerview"
        android:clipToPadding="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>

短信类

public class SMSmessage {
    private String senderName, smsContent;

    public SMSmessage(String senderName, String smsContent) {
        this.senderName = senderName;
        this.smsContent = smsContent;
    }

    public String getSenderName() {
        return senderName;
    }

    public String getSmsContent() {
        return smsContent;
    }
}

【问题讨论】:

    标签: java android xml android-recyclerview android-adapter


    【解决方案1】:
    • 首先使用一个父布局,它是线性布局,然后创建包含任何布局(如线性或相对)的子布局,然后您可以创建第二个子布局,在子布局中您将使用卡片视图和其他组件,如 textview或在卡片视图中编辑文本

    否则约束布局最好开发这个布局

    例如

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_sectionwithexpandability_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="2"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_weight="1"
        android:layout_height="wrap_content">
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ll_sectionheader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="10dp"
        android:weightSum="100">
    
        <TextView
            android:id="@+id/tv_sectionheader_expandcollapsearrow"
            android:clickable="true"
            android:focusable="true"
            android:layout_weight="10"
            android:text="Testing"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="10dp"
            android:textColor="?android:attr/textColorPrimary"
            style="@android:style/TextAppearance.Large" />
    
        <TextView
            android:id="@+id/tv_sectionheader_title"
            android:layout_weight="90"
            android:layout_width="0dp"
            android:text="testing"
            android:layout_height="wrap_content"
            style="@android:style/TextAppearance.Large" />
       </LinearLayout>
       </android.support.v7.widget.CardView>
      </LinearLayout>
      <!-- I WANT ALL THE CARD VIEWS TO BE ADDED INSIDE THIS LINEARLAYOUT (ll_section_cards) -->
      <LinearLayout
       android:layout_width="match_parent"
        android:layout_weight="1"
       android:layout_height="wrap_content">
       <android.support.v7.widget.CardView
           android:layout_width="match_parent"
           android:layout_height="match_parent">
       <LinearLayout
        android:id="@+id/ll_section_cards"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
      <TextView
               android:id="@+id/te"
               android:layout_weight="90"
               android:layout_width="wrap_content"
               android:text="testing"
               android:layout_height="wrap_content"
               style="@android:style/TextAppearance.Large" />
      </LinearLayout>
       </android.support.v7.widget.CardView>
      </LinearLayout>
    </LinearLayout>
    

    【讨论】:

    • 如何以编程方式添加CardView?我还希望能够以编程方式添加超过 1 个CardView
    【解决方案2】:

    编辑:您的问题属于 XY 问题:enter link description here

    您的整个架构/模式似乎不合适。

    您也许可以调整您的代码,因此在“OnBind”方法中,您检查下一个 n+1 对象是否是 SMSMessage 并将该批次添加到线性布局......并且以某种方式记录它们已经被“绑定”以避免双重绑定...但是您还需要检测该查看器何时未绑定...这一切似乎都在与框架希望您做事的方式作斗争。

    我建议让 API(或“本地服务”)将 API 数据(最好使用像 JacksonMapper 这样的 ObjectMapper)转换为一个看起来更像的类:

    import java.util.List;
    
    public class SMSMessageCollection {
    
        private List<SMSMessage> smsMessages;
        private String headerText;
        private boolean hasStartingRVLine;
        private boolean hasEndingRVLine;
    
        public SMSMessageCollection(String headerText, boolean hasStartingRVLine, boolean hasEndingRVLine) {
            this.headerText = headerText;
            this.hasStartingRVLine = hasStartingRVLine;
            this.hasEndingRVLine = hasEndingRVLine;
        }
    
        //CUSTOM "ADDER":
        public void addSMSMessagesToCollection(List<SMSMessage> smsMessagesToAdd){
            this.smsMessages.addAll(smsMessagesToAdd);
        }
    
        //GETTER AND SETTER HERE -> OR USE LOMBOK...
    
    }
    

    这个类包含一个List&lt;SMSMessages&gt;,所以当对象被绑定到回收器适配器时,你可以遍历列表并将它们添加到线性布局中。

    这就是我的 Activity 的样子...获取 API 数据并制作一个 SMSMessageCollection(s) 列表,然后可以通过一个 ViewHolder 将其传递给适配器...

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    import org.json.JSONArray;
    
    import java.io.IOException;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //This would be fetched using say Volley...and the structure should MATCH the class we have made...
            //Otherwise...make a "service class" to convert the API response to the SMSMessageCollection
            JSONArray apiDataModels = new JSONArray();
    
            // Jackson ObjectMapper will turn the API data in to a List or POJOs...in like two lines.
            try {
                List<SMSMessageCollection> smsMessageCollections = new ObjectMapper()
                        .readValue(apiDataModels.toString(),new TypeReference<List<SMSMessageCollection>>(){});
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    }
    

    因此,在 adpater 的 OnBindViewHolder 方法中,您可以获取该部分的 List 并以编程方式将它们添加到被注入的 ViewHolder 的 LienarLayout。

    【讨论】:

    • 这个需要进入适配器吗?我将如何在 CardView 中添加文本?片段是唯一可以这样做的地方。
    • 如果您不能回答我的问题并想出更好的解决方案,请删除您的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-02
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多