Recently read a lot of RecyclerView use articles, has been dizzy, completely do not know what routine is. A lot of people code directly, but don’t specify how to use the code, so they decide to write their own, clear the way. And help those new to learning Android.

In this paper, the source code, see https://github.com/huanshen/Learn-Android/tree/master/recycleTest

1. RecyclerView of a single item

First, recycleView needs to be introduced, so in build. Gradle (Model) :

The compile 'com. Android. Support: recyclerview - v7:26.0 +'Copy the code

Let’s start writing the layout file:

<? The 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" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/my_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical"/> </RelativeLayout>Copy the code

It’s kind of taking up space on the screen for recyclerView, but we have to add items to it, and items have to have their own layout, so let’s go ahead and write the following layout.

<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"  android:text="wenzi " android:id="@+id/text"/> </LinearLayout>Copy the code

Now that the layout is written, the next step is how to display the data on the View. This of course has to use the adapter, recycleView has its own adapter, we just need to inherit, and then write the specific processing code, the details are as follows, there is a detailed analysis behind.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { public String[] datas = null; public MyAdapter(String[] data) { datas = data; } // Create a new View, @override public ViewHolder onCreateViewHolder(ViewGroup ViewGroup, int viewType) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item,viewGroup,false); ViewHolder vh = new ViewHolder(view); return vh; } @override public void onBindViewHolder(ViewHolder ViewHolder, int position) { viewHolder.mTextView.setText(datas[position]); } @override public int getItemCount() {return datas.length; } // Custom ViewHolder, Public class ViewHolder extends RecyclerView.ViewHolder {public TextView mTextView; public ViewHolder(View view){ super(view); mTextView = (TextView) view.findViewById(R.id.text); }}}Copy the code

Let’s take a closer look at what is written after inheritance, starting with the MyAdapter constructor, which is used to pass in the required data. It’s usually an array or a linked list, that’s what makes a list.

The second one is onCreateViewHolder, which I translate to create view container, which holds the Item view. Get the view of the item and then put it in the container.

The onBindViewHolder is the binding of each item in the container so that we can map the data to the View for display.

And then getItemCount, which just returns a number, how many were created at the end.

Finally, we have a custom ViewHolder inherited from RecyclerView.viewholder. We need to put each item into the ViewHolder so that we can bind it. There’s an mTextView defined here, and notice that it also appears in onBindViewHolder.

Take a good look at the code, then read the analysis above, and you should know how to use it.

Next, we’ll start using them, as shown in the following code:

private RecyclerView mRecyclerView; private RecyclerView.LayoutManager mLayoutManager; private RecyclerView.Adapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view); MLayoutManager = new LinearLayoutManager(this); mRecyclerView.setLayoutManager(mLayoutManager); / / if you can determine the height of each item is fixed, set this option may improve performance. MRecyclerView setHasFixedSize (true); MAdapter = new MyAdapter(new String[]{"1231","43252345","2342342"}); mRecyclerView.setAdapter(mAdapter); }Copy the code

First we need to find the old RecyclerView big container, then we create a default linear Layoutmanger and set RecyclerView to linear. Then we pass the data into MyAdapter, create an instance of it, and call setAdapter.

 

2, multiple item recycleView realization

What we’ve shown is that there’s only one item, and they all look the same. Can we have multiple styles? The answer is yes.

As shown in the figure above, we make it odd and even. Of course, we are completely free to implement graphs and no graphs.

That this specific how to achieve it, or on the basis of the last code to modify.

First, let’s add a new style called Item1.xml

<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:id="@+id/root" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="56dp" android:text="wenzi " android:background="@color/colorAccent" android:layout_margin="10dp" android:id="@+id/text"/> </LinearLayout>Copy the code

Then we started adding code to implement multiple items of the face, mainly in our own adapter, leaving the activity code untouched.

    private final int ITEM = 1;
    private final int ITEM1 = 2;
Copy the code

First we define two constants to represent two different types. Since there are two types, it is natural to define two different Viewholds. The specific code is as follows:

Public class ImageHolder extends RecyclerView.ViewHolder {public TextView mTextView; public ImageHolder(View view){ super(view); mTextView = (TextView) view.findViewById(R.id.text); } } public class ColorHolder extends RecyclerView.ViewHolder{ public TextView mTextView; public ColorHolder(View view){ super(view); mTextView = (TextView) view.findViewById(R.id.text); }}Copy the code

We also need to create two different viewHold containers, so how do we know which one we need to create?

This is where getItemViewType comes in handy, and this is the function that determines the type for us, depending on the location.

Since our data is relatively simple, I divide it by odd and even. So when we do that, we have to provide the data and also provide the category of the data, so that we know which view is used to display that data.

public int getItemViewType(int position) {
        if (position % 2 == 0){
            return ITEM;
        }
        return ITEM1;
    }
Copy the code

Once we have delineated the data type, we can create the viewHold.

// Create a new View, @override public recyclerView. ViewHolder onCreateViewHolder(ViewGroup ViewGroup, int viewType) { if (viewType == ITEM) { View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false); ImageHolder vh = new ImageHolder (view); return vh; }else{ View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item1, viewGroup, false); ColorHolder vh = new ColorHolder(view); return vh; }}Copy the code

In the above code, we refer to different layouts according to different types.

Once created, it’s time to bind the data. The specific code is as follows:

@override public void onBindViewHolder(recyclerView. ViewHolder ViewHolder, int position) { if (viewHolder instanceof ImageHolder) { //Toast.makeText(MainActivity.this, datas[position], Toast.LENGTH_SHORT).show(); ((ImageHolder)viewHolder).mTextView.setText(datas[position]); viewHolder.itemView.setTag(position); }else { ((ColorHolder)viewHolder).mTextView.setText(datas[position]); viewHolder.itemView.setTag(position); }}Copy the code

When binding, we need to determine the viewHold type so that we can bind data to the view correctly.

Well, here we are done, I believe you should be able to master recycleView.

 

3. Generation of click events

We want each item to pop up its corresponding position when clicked.

First, we implement the View.OnClickListener interface to make the Item clickable.

public  class ImageHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView mTextView;
        public ImageHolder(View view){
            super(view);
            mTextView = (TextView) view.findViewById(R.id.text);
            view.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (mOnRvItemClick != null)
                mOnRvItemClick.onItemClick(view, getAdapterPosition());
        }
    }
Copy the code

Here, we implement the interface in ImageHolder, overriding the onClick method. We’ll see what’s inside the method later. The parameter of this method does not have position, so we need to do some processing. Position position is obtained mainly through getAdapterPosition.

We define an item click interface

public interface onRecyclerViewItemClick {
        void onItemClick(View v, int position);
    }
Copy the code

So here we’ve defined an onRecyclerViewItemClick interface, and the internal method is onItemClick, so you can see we have position.

public MyAdapter(String[] data, onRecyclerViewItemClick onRvItemClick) {
        datas = data;
        mOnRvItemClick = onRvItemClick;
    }
Copy the code

Then when we initialize, we pass the onRecyclerViewItemClick instance onRvItemClick to the private mOnRvItemClick parameter; The call is then made in onClick, as described earlier.

Finally, we just call it.

mAdapter = new MyAdapter(data, new MyAdapter.onRecyclerViewItemClick() { @Override public void onItemClick(View v, Int position) {toast.maketext (mainactivity. this, "" + position +" "line ", toast.length_short).show(); }}); mRecyclerView.setAdapter(mAdapter);Copy the code

 

4. Add dividers

RecyclerView has a default dividing line method: DividerItemDecoration.

Just call it like this:

        mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
Copy the code

The dividing line is also horizontal or vertical. If we need to customize our own divider, that’s fine. We only need extends RecyclerView. ItemDecoration can rewrite some of the method.

  1 package com.example.shenjiaqi.httpshiyong;
  2 
  3 import android.annotation.SuppressLint;
  4 import android.content.Context;
  5 import android.content.res.TypedArray;
  6 import android.graphics.Canvas;
  7 import android.graphics.Rect;
  8 import android.graphics.drawable.Drawable;
  9 import android.support.annotation.NonNull;
 10 import android.support.v7.widget.LinearLayoutManager;
 11 import android.support.v7.widget.RecyclerView;
 12 import android.view.View;
 13 import android.widget.LinearLayout;
 14 
 15 /**
 16  * Created by shenjiaqi on 2017/10/22.
 17  */
 18 
 19 public class MyDecoration extends RecyclerView.ItemDecoration {
 20     /**
 21      *
 22      * @param outRect 边界
 23      * @param view recyclerView ItemView
 24      * @param parent recyclerView
 25      * @param state recycler 内部数据管理
 26      *//*
 27     @Override
 28     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
 29         //设定底部边距为1px
 30         *//*outRect.set(0, 0, 0, 30);*//*
 31     }*/
 32 
 33     public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
 34     public static final int VERTICAL = LinearLayout.VERTICAL;
 35 
 36     private static final int[] ATTRS = new int[]{ android.R.attr.listDivider };
 37 
 38     private Drawable mDivider;
 39 
 40     /**
 41      * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}.
 42      */
 43     private int mOrientation;
 44 
 45     private final Rect mBounds = new Rect();
 46 
 47     /**
 48      * Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a
 49      * {@link LinearLayoutManager}.
 50      *
 51      * @param context Current context, it will be used to access resources.
 52      * @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}.
 53      */
 54     public MyDecoration(Context context, int orientation) {
 55         final TypedArray a = context.obtainStyledAttributes(ATTRS);
 56         mDivider = a.getDrawable(0);
 57         a.recycle();
 58         setOrientation(orientation);
 59     }
 60 
 61     /**
 62      * Sets the orientation for this divider. This should be called if
 63      * {@link RecyclerView.LayoutManager} changes orientation.
 64      *
 65      * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
 66      */
 67     public void setOrientation(int orientation) {
 68         if (orientation != HORIZONTAL && orientation != VERTICAL) {
 69             throw new IllegalArgumentException(
 70                     "Invalid orientation. It should be either HORIZONTAL or VERTICAL");
 71         }
 72         mOrientation = orientation;
 73     }
 74 
 75     /**
 76      * Sets the {@link Drawable} for this divider.
 77      *
 78      * @param drawable Drawable that should be used as a divider.
 79      */
 80     public void setDrawable(@NonNull Drawable drawable) {
 81         if (drawable == null) {
 82             throw new IllegalArgumentException("Drawable cannot be null.");
 83         }
 84         mDivider = drawable;
 85     }
 86 
 87     @Override
 88     public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
 89         if (parent.getLayoutManager() == null) {
 90             return;
 91         }
 92         if (mOrientation == VERTICAL) {
 93             drawVertical(c, parent);
 94         } else {
 95             drawHorizontal(c, parent);
 96         }
 97     }
 98 
 99     @SuppressLint("NewApi")
100     private void drawVertical(Canvas canvas, RecyclerView parent) {
101         canvas.save();
102         final int left;
103         final int right;
104         if (parent.getClipToPadding()) {
105             left = parent.getPaddingLeft();
106             right = parent.getWidth() - parent.getPaddingRight();
107             canvas.clipRect(left, parent.getPaddingTop(), right,
108                     parent.getHeight() - parent.getPaddingBottom());
109         } else {
110             left = 0;
111             right = parent.getWidth();
112         }
113 
114         final int childCount = parent.getChildCount();
115         for (int i = 0; i < childCount; i++) {
116             final View child = parent.getChildAt(i);
117             parent.getDecoratedBoundsWithMargins(child, mBounds);
118             final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
119             final int top = bottom - mDivider.getIntrinsicHeight();
120             mDivider.setBounds(left, top, right, bottom);
121             mDivider.draw(canvas);
122         }
123         canvas.restore();
124     }
125 
126     @SuppressLint("NewApi")
127     private void drawHorizontal(Canvas canvas, RecyclerView parent) {
128         canvas.save();
129         final int top;
130         final int bottom;
131         if (parent.getClipToPadding()) {
132             top = parent.getPaddingTop();
133             bottom = parent.getHeight() - parent.getPaddingBottom();
134             canvas.clipRect(parent.getPaddingLeft(), top,
135                     parent.getWidth() - parent.getPaddingRight(), bottom);
136         } else {
137             top = 0;
138             bottom = parent.getHeight();
139         }
140 
141         final int childCount = parent.getChildCount();
142         for (int i = 0; i < childCount; i++) {
143             final View child = parent.getChildAt(i);
144             parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
145             final int right = mBounds.right + Math.round(child.getTranslationX());
146             final int left = right - mDivider.getIntrinsicWidth();
147             mDivider.setBounds(left, top, right, bottom);
148             mDivider.draw(canvas);
149         }
150         canvas.restore();
151     }
152 
153     @Override
154     public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
155                                RecyclerView.State state) {
156         int childAdapterPosition = parent.getChildAdapterPosition(view);
157 
158         int lastCount = parent.getAdapter().getItemCount() - 1;
159         //如果当前条目与是最后一个条目,就不设置divider padding
160         if (childAdapterPosition == lastCount) {
161             outRect.set(0, 0, 0, 0);
162             return;
163         }
164         if (mOrientation == VERTICAL) {
165             outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
166         } else {
167             outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
168         }
169     }
170 }
Copy the code

View Code

 

In order to use our own dividing line

Create a file in divider. XML in drawable

<? The XML version = "1.0" encoding = "utf-8"? > <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <gradient android:centerColor="#ff00ff00" android:endColor="#ff0000ff" android:startColor="#ffff0000" android:type="linear" /> <size android:height="4dp"/> </shape>Copy the code

We then put an item in the style file. The name is called Android :listDivider; Import the file above.

<resources> <! -- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <! -- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="android:listDivider">@drawable/divider</item> </style> </resources>Copy the code