drenfro87 drenfro87 - 4 months ago 22
Android Question

Cardview is all going into one card

I am trying to create a card view for a checklist that will be going into a app for school. All of the items in the ArrayList are going into one card and i cant figure out why. I have looked at every tutorial that i can find but no luck.
Here is the relevant code. Any and all help is greatly appreciated.

Activity

recyclerView = (RecyclerView) findViewById(R.id.masterListRecView);
recyclerView.setHasFixedSize(true);

layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());

theList = new ArrayList<MasterListItem>();

theList.add(new MasterListItem("Test Item1",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item2",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item3",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item4",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item5",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item6",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item7",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item8",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item9",new Date(),new Date(),"here are some notes",false));
theList.add(new MasterListItem("Test Item10",new Date(),new Date(),"here are some notes",false));

masterListAdapter = new RecViewAdapter(theList);
recyclerView.setAdapter(masterListAdapter);

masterListAdapter.notifyDataSetChanged();


RecycleView Adapter

public class RecViewAdapter extends RecyclerView.Adapter<RecViewAdapter.MyViewHolder> {
TextView title;
TextView dueDate;
TextView completedDate;
TextView notes;
CheckBox completed;
private ArrayList<MasterListItem> theList;
//private LayoutInflater inflater;

public RecViewAdapter(ArrayList<MasterListItem> theList) {
this.theList = theList;
//inflater = LayoutInflater.from(context);
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.master_list_item,parent,false);

MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
title = holder.title;
dueDate = holder.dueDate;
completedDate = holder.completedDate;
notes = holder.notes;
completed = holder.completed;

title.setText(theList.get(position).getTitle());
dueDate.setText(theList.get(position).getDueDate().toString());
completedDate.setText(theList.get(position).getCompletedDate().toString());
notes.setText(theList.get(position).getNotes());
completed.setChecked(theList.get(position).isCompleted());
}



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

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}


public class MyViewHolder extends RecyclerView.ViewHolder{
private TextView title;
private TextView dueDate;
private TextView completedDate;
private TextView notes;
private CheckBox completed;
public MyViewHolder(View itemView){
super(itemView);
this.title = (TextView) itemView.findViewById(R.id.masterListTitle);
this.dueDate = (TextView) itemView.findViewById(R.id.masterListDueDate);
this.completedDate = (TextView) itemView.findViewById(R.id.masterListCompletedDate);
this.notes = (TextView) itemView.findViewById(R.id.masterListNotes);
this.completed = (CheckBox) itemView.findViewById(R.id.masterListCompleted);
}
}



}


RecycleView XML

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="edu.uco.weddingcrashers.hitched.MasterWeddingList">

<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+"
android:id="@+id/addTaskButton"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true" />

<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:id="@+id/masterListRecView"
>



</android.support.v7.widget.RecyclerView>


</RelativeLayout>


Card XML

<?xml version="1.0" encoding="utf-8"?>


<android.support.v7.widget.CardView
android:id="@+id/masterListCardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
card_view:cardCornerRadius="4dp"
xmlns:android="http://schemas.android.com/apk/res/android">


<!--
android:layout_alignParentStart="true"
android:layout_gravity="center"
android:layout_below="@+id/addTaskButton"
-->


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">


<TextView
android:id="@+id/masterListTitle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="test title" />
<TextView
android:id="@+id/masterListDueDate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="test title" />
<TextView
android:id="@+id/masterListCompletedDate"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="test title" />
<TextView
android:id="@+id/masterListNotes"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="test title" />
<CheckBox
android:id="@+id/masterListCompleted"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Completed"
android:editable="false"
android:layout_gravity="center_horizontal" />
</LinearLayout>


</android.support.v7.widget.CardView>


Once again Thank you so much!

Answer

You must add divider between your RecyclerView item. Adding divider and decoration to RecyclerView is different from other list views. You can achieve this by this answer:

Unlike ListView, the RecyclerView class has no divider-related parameters. Instead, you need to extend ItemDecoration, a RecyclerView's inner class:

An ItemDecoration allows the application to add a special drawing and layout offset to specific item views from the adapter's data set. This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more.

All ItemDecorations are drawn in the order they were added, before the item views (in onDraw() and after the items (in onDrawOver(Canvas, RecyclerView, RecyclerView.State).

Vertical spacing ItemDecoration Extend ItemDecoration, add custom constructor which takes space height as a parameter and override getItemOffsets():

public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {

    private final int mVerticalSpaceHeight;

    public VerticalSpaceItemDecoration(int mVerticalSpaceHeight) {
        this.mVerticalSpaceHeight = mVerticalSpaceHeight;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
            RecyclerView.State state) {
        outRect.bottom = mVerticalSpaceHeight;
    }
}

If you don't want to insert space below the last item, add the following condition:

if (parent.getChildAdapterPosition(view) !=
                              parent.getAdapter().getItemCount() - 1) {
            outRect.bottom = mVerticalSpaceHeight;
}

Note: you can also modify outRect.top, outRect.left and outRect.right properties for desired effect.

Divider ItemDecoration Extend ItemDecoration and override onDraw():

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};

    private Drawable mDivider;

    /**
     * Default divider will be used
     */
    public DividerItemDecoration(Context context) {
        final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
        mDivider = styledAttributes.getDrawable(0);
        styledAttributes.recycle();
    }

    /**
     * Custom divider will be used
     */
    public DividerItemDecoration(Context context, int resId) {
        mDivider = ContextCompat.getDrawable(context, resId);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
}

You can either call the first constructor that uses the default Android divider attributes, or the second one that uses your own drawable, for example drawable/divider.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <size
            android:height="1dp" />
    <solid android:color="#ff992900" />
</shape>

Note: if you want the divider to be drawn over your items, override onDrawOver() instead.

Usage

To use your new class add VerticalSpaceItemDecoration or DividerSpaceItemDecoration to RecyclerView, for example in your fragment's onCreateView():

private static final int VERTICAL_ITEM_SPACE = 48;
private RecyclerView mUiRecyclerView;
private LinearLayoutManager mLinearLayoutManager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_feed, container, false);

    mUiRecyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_home_recycler_view);
    mLinearLayoutManager = new LinearLayoutManager(getActivity());
    mUiRecyclerView.setLayoutManager(mLinearLayoutManager);

    //add ItemDecoration
    mUiRecyclerView.addItemDecoration(new VerticalSpaceItemDecoration(VERTICAL_ITEM_SPACE));
    //or
    mUiRecyclerView.addItemDecoration(
            new DividerItemDecoration(getActivity());
    //or
    mUiRecyclerView.addItemDecoration(
            new DividerItemDecoration(getActivity(), R.drawable.divider));

    mUiRecyclerView.setAdapter(...);

    return rootView;
}

There's also Lucas Rocha's library which is supposed to simplify the item decoration process. Haven't tried it though.

Among its features are:

A collection of stock item decorations including:

  • Item spacing Horizontal/vertical dividers.
  • List item
Comments