Friday, July 31, 2015

Diving into the RecyclerView

The next major element we are going to introduce is the RecyclerView: https://developer.android.com/training/material/lists-cards.html.

The first thing we need to do is bring in the v7 RecyclerView Libraryhttp://developer.android.com/tools/support-library/features.html by adding one lines to the build.gradle file.

build.gradle
compile 'com.android.support:recyclerview-v7:22.2.0'

The first step is to create the model that one will use to build the list. While in most applications today this model will come from a RESTFul API, we will simply create the model in the application, e.g.,  we can create three things as follows:

Add a private list of things to the MainActivity class.

MainActivity.java
private List<String> things;

and then initialize it in the onCreate method.

MainActivity.java
things = new ArrayList<String>();
things.add("one");
things.add("two");
things.add("three");

Now that we have the model, we define the view, first by updating styles.xml:

styles.xml
<style name="ListContainer">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:paddingTop">8dp</item>
</style>
<style name="ListItem">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
</style>
<style name="ListContent">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
</style>
<style name="ListSingleLine">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:paddingLeft">16dp</item>
    <item name="android:paddingTop">16dp</item>
    <item name="android:paddingRight">16dp</item>
    <item name="android:paddingBottom">20dp</item>
    <item name="android:textSize">16sp</item>
</style>
<style name="ListDivider">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">1dp</item>
    <item name="android:background">?android:attr/listDivider</item>
</style>

and creating thing.xml in the res/layout folder:

thing.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/ListItem">
    <RelativeLayout
        android:id="@+id/content"
        style="@style/ListContent">
        <TextView
            android:id="@+id/name"
            style="@style/ListSingleLine" />
    </RelativeLayout>
    <View
        style="@style/ListDivider"
        android:layout_below="@id/content" />
</RelativeLayout>

and updating activity_main.xml; replacing the TextView with the following:

activity_main.xml
<android.support.v7.widget.RecyclerView
    android:id="@+id/things"
    android:layout_below="@id/toolbar"
    style="@style/ListContainer" />

With the model and the view in place we need to connect the two (controller type code).

In the OnCreate method of the MainActivity we add the following:

MainActivity.java
RecyclerView thingRV = (RecyclerView) findViewById(R.id.things);
thingRV.setHasFixedSize(true);
thingRV.setLayoutManager(new LinearLayoutManager(this));

The next step is to use the View Holder pattern: http://developer.android.com/training/improving-layouts/smooth-scrolling.html#ViewHolder.  Create ThingViewHolder in MainActivity.

MainActivity.java
public class ThingViewHolder extends RecyclerView.ViewHolder {

    String id;
    TextView name;

    ThingViewHolder(View view) {
        super(view);
        name = (TextView)view.findViewById(R.id.name);
    }

}

The key then is to create ThingAdapter in MainActivity (seems that I have to stare as this code every time I see it).

MainActivity.java
public class ThingAdapter extends RecyclerView.Adapter<ThingViewHolder> {

    List<String> things;

    ThingAdapter(List<String> things) {
        this.things = things;
    }

    public ThingViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.thing, viewGroup, false);
        return new ThingViewHolder(view);
    }

    public int getItemCount() {
        return things.size();
    }

    public void onBindViewHolder(ThingViewHolder viewHolder, int i) {
        viewHolder.id = things.get(i);
        viewHolder.name.setText(things.get(i));
    }

}

And finally, we hand an instance of ThingAdapter to the thingRV RecyclerView in the onCreate method of MainActivity.java.

MainActivity.java
thingRV.setAdapter(new ThingAdapter(things));

Seems like a lot of work to get the three words one, two, and three to show up in a list on the screen.

Now we make the words clickable by updating the ThingViewHolder class as follows:

MainActivity.java
public class ThingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    String id;
    TextView name;

    ThingViewHolder(View view) {
        super(view);
        name = (TextView)view.findViewById(R.id.name);
        view.setOnClickListener(this);
    }

    public void onClick(View view) {
        Snackbar
                .make(findViewById(R.id.snackbarPosition), name.getText(), Snackbar.LENGTH_LONG)
                .show();
    }
}

No comments:

Post a Comment