Before starting to show how we can make a list with the recycler view we go to answer to the mother of the question: why should we do this? How can this thing help us? The answer is very simple: because of personalization. In this way we can easily use a layout made by us, define different action for every object inside this layout, and the inflate all in a recycler view and make them appear like a list. Let’s show how!
First of all create a new xml layout resource (card_example.xml here) where define how the list row will appear. I write a very simple example that will appear very similar to one of the list view default style, but you can personalize all you want.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingBottom="2dp" android:paddingTop="2dp" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" android:id="@+id/layoutCard" android:background="?android:attr/selectableItemBackground"> <TextView android:id="@+id/textViewAreaName" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Some text" android:textAllCaps="true" android:textStyle="bold" android:layout_gravity="center"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/checkBoxArea" android:checked="false" android:clickable="false" android:layout_gravity="center" /> </LinearLayout>
As you can see I realized some small arrangement, like set the padding, make the checkbox not clickable (we will see why). At the same way we can define what we like in the layout.
After that we have to create an adapter (StringArrayAdapter.java) that will process our data. In this example our data are a simple array of string but you can process all what you want, useful to set a complex row layout.
public class StringArrayAdapter extends RecyclerView.Adapter<StringArrayAdapter.StringHolder>{ private List<String> stringList; public StringArrayAdapter(List<String> stringList) { this.stringList = stringList; } @Override public StringHolder onCreateViewHolder(ViewGroup parent, int viewType) { //Inflate the view defined in the card_example.xml and return a new StringHolder View view = LayoutInflater.from(parent.getContext()). inflate(R.layout.card_example, parent, false); return new StringHolder(view); } //Here we can set all the action that we want to make, for example change the status of the checkbox //on the all view click @Override public void onBindViewHolder(final StringHolder holder, int position) { holder.textViewString.setText(stringList.get(position)); holder.view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holder.checkBox.setChecked(!holder.checkBox.isChecked()); } }); } //Simple return the size of our list @Override public int getItemCount() { return stringList.size(); } protected class StringHolder extends RecyclerView.ViewHolder { private final View view; private final TextView textViewString; private final CheckBox checkBox; //Retrieve the view above on the class constructor public StringHolder(View v) { super(v); this.view = v; this.textViewString = (TextView) v.findViewById(R.id.textViewString); this.checkBox = (CheckBox) v.findViewById(R.id.checkBox); } } }
In a few words what we made is to get the list of strings that are our data, create a new StringHolder (based on ViewHolder) for any row inside the predefined onCreateViewHolder. Inside the StringHolder constructor we set all the object previous defined in the xml layout and the, finally, we manage the row and make it to do some work inside the onBindViewHolder method. In this example we set the text of our textViewString based on the stringList and set a click listener on all the view where, at the action, change the status of the checkbox.
Now we have almost done! In our activity (or fragment, practically where you have your RecyclerView) simply set the RecyclerView as you prefer and set it the above adapter.
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); //Initialize a simple array of string for example ArrayList<String> stringArrayList = new ArrayList<>(); for (int c=0; c<10; c++) { stringArrayList.add("Text " + c); } //Create the adapter by the class that we had create StringArrayAdapter stringArrayAdapter = new StringArrayAdapter(stringArrayList); //Initialize the recycler view of our example with a default vertical linear layout //and set it the adapter created above RecyclerView recyclerViewExample = (RecyclerView) findViewById(R.id.recyclerViewExample); LinearLayoutManager linearLayoutManagerList = new LinearLayoutManager(this); linearLayoutManagerList.setOrientation(LinearLayoutManager.VERTICAL); recyclerViewExample.setLayoutManager(linearLayoutManagerList); recyclerViewExample.setItemAnimator(new DefaultItemAnimator()); recyclerViewExample.setHasFixedSize(true); recyclerViewExample.setAdapter(stringArrayAdapter); } }
To being more clear check the example. We create the our data to give to the adapter, here by a simple for, then create a new StringArrayAdapter object and, after we have initialized the RecyclerView, we set it the adapter. By this simple action the recycler will call all the adapter methods previously seen and we have done all.
Before I set the checkbox not clickable in the xml, the why is simple. I need this to be sure that the only click action that can change the checkbox status is made by the parent view, as written in the adapter class. Denying the click to the checkbox is the best way to make it looks like enabled and, meantime, avoid any possible “double” action, one from the our layout click listener and the other one from the checkbox.
Two more trick
The ListView, by default, implements a click listener interface, where retrieve the row click to made some actions. The RecyclerView does not have this possibility, but we could achieve it by the adapter in a very simple way.
First of all we have to create a new interface in the adapter class, in our example inside StringArrayAdapter.
public interface OnClickListener { void onClick(int position); }
Then we add a private onClickListener object to the main adapter class and the set method.
private OnClickListener onClickListener = null; public void setOnClickListener(OnClickListener onClickListener) { this.onClickListener = onClickListener; }
At the end just call the onClick method from the interface where we have already set an OnClickListener for the row view.
holder.view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { holder.checkBox.setChecked(!holder.checkBox.isChecked()); if(onClickListener != null) { onClickListener.onClick(position); } } });
Now we just need to call the setOnClickListener method of our adapter where we need to retrieve the click and manage it.
stringArrayAdapter.setOnClickListener(new StringArrayAdapter.OnClickListener() { @Override public void onClick(int position) { //Do something } });
The second trick is to add a divider between the rows. To made this we need to create a class that extends the RecyclerView.ItemDecoration and make it able to draw the divider. I paste an example of this.
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; public class DividerItemsRecyclerView extends RecyclerView.ItemDecoration{ private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; private static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private final Drawable mDivider; private int mOrientation; public DividerItemsRecyclerView(Context context) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(); } private void setOrientation() { mOrientation = LinearLayoutManager.VERTICAL; } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } private void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount - 1; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } private void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount - 1; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } }
Then the only thing that you have to do is to add the above DividerItemsRecyclerView to your RecyclerView.
recyclerView.addItemDecoration(new DividerItemsRecyclerView(this)); //Where 'this' is a valid context
That’s all, for any question just post a comment!
L'articolo Android: create list with the recycler view sembra essere il primo su -Bottyland-.