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