1. What is RecyclerView?
According to the official instructions of Google:
A flexible view for providing a limited window into a large data set.
It can display flexible views of large data sets in limited windows.
So we can understand that an appropriate use scenario for RecyclerView is that due to size constraints, the user's device cannot display all items at once, and the user needs to scroll up and down to see more items. Items that roll out of the visible area are recycled and reused when the next item is visible.
Caching entries is a very useful way to reduce memory overhead and CPU computing, because it means that we don't have to create new entries every time, so as to reduce memory overhead and CPU computing, but also can effectively reduce the screen carton, to ensure smooth sliding.
RecyclerView doesn't care about visual effects.
But what's the difference between ListView and ListView? We've been using ListView for a long time, and it can do the same. From its class name, RecyclerView stands for the meaning that I only care about Recycler View, that is, RecyclerView only recycles and reuses View, and other developers can set it up by themselves. You want another layout? Insert another Layout Manager. Do you want different animations? Insert an ItemAnimator, and so on. You can see that it is highly decoupled and gives you full customization freedom (so you can easily implement ListView,GirdView, Waterfall Stream and other effects through this control).
2. Introducing Recycler View
RecyclerView is part of the Support Library. So you just need to add the following dependencies in app/build.gradle to use them immediately:
dependencies {
compile 'com.android.support:recyclerview-v7:25.3.1'
}
Add:
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Then introduce RecyclerView into the page.
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
OK, from now on, let's start to understand it step by step.
3. Use Recycler View
The following table shows the most important classes used in the data using RecyclerView. These classes are the internal classes of RecyclerView. If you want to use RecyclerView, you need to do the following:
Class | function |
---|---|
Adapter | Handling data set merging is responsible for binding views |
ViewHolder | Holding all View s for binding data or operations |
LayoutManager | Responsible for the display of views and other related operations |
ItemDecoration | Responsible for drawing the dividing line near Item |
ItemAnimator | Add animation effects to Item's general operations, such as adding or deleting entries, etc. |
We can see the basic structure of RecyclerView more intuitively from the following figure:
Next, I will describe the content of each class or interface and how to use it.
3.1 RecyclerView.ViewHolder
The basic use of ViewHolder is to store View objects. The Android team recommended the ViewHolder design pattern long ago, but did not require developers to use the ViewHolder pattern in the Adapter. Now for this new RecyclerView.Adapter, we have to implement and use this pattern.
It's strange that Google officials have waited so long to force ViewHolder mode, but it's better late than never. If you don't know the ViewHolder mode, check out Android training Hold View Objects in a View Holder . In addition, there are a lot of articles about ListView optimization on the Internet. Emphasis of the interview.
One thing is specifically for Recycler View. The ViewHolder subclass can access the root view of the ViewHolder by accessing the itemView, a public member. So you don't need to store it in the ViewHolder subclass.
Below is the code for the sample ViewHolder, which is the internal class of the sample Adapter:
public static class MyViewHolder extends RecyclerView.ViewHolder{
TextView tv;
public MyViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.tv);
}
}
3.2 Adapter
Adapter plays two roles. One is to create Item-Layout corresponding to different ViewType s, and the other is to bind data to the correct View by accessing the data set merge. This requires us to rewrite the following three methods:
- Public VH on CreateViewHolder (ViewGroup parent, int viewType) creates an Item view and returns the corresponding ViewHolder
public void onBindViewHolder(VH holder, int position) binds data to the correct Item view.
public int getItemCount() returns the number of item s held by the Adapter
The sample code is as follows:
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)
.inflate(R.layout.item_recycler_view,parent,false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv.setText(mDatas.get(position));
}
@Override
public int getItemCount() {
return mDatas.size();
}
Therefore, a basic RecyclerView.Adapter is as follows:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private Context context;
private List<String> mDatas;
public RecyclerAdapter(Context context, List<String> mDatas) {
this.context = context;
this.mDatas = mDatas;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context)
.inflate(R.layout.item_recycler_view, parent, false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv.setText(mDatas.get(position));
}
@Override
public int getItemCount() {
return mDatas == null ? 0 : mDatas.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv;
public MyViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.tv);
}
}
}
3.3 RecyclerView.LayoutManager
LayoutManager's responsibility is to place Item s and to decide when to recycle and reuse them. It has a default implementation: Linear Layout Manager, which can be used for vertical and horizontal lists.
RecyclerView.LayoutManager is an abstract class. RecyclerView provides us with three implementation classes:
- Linear Layout Manager's current manager supports both horizontal and vertical.
- GridLayout Manager Grid Layout Manager
- Staggered Grid Layout Manager Waterfall Flow Layout Manager
3.3.1 LinearlayoutManager
LinearlayoutManager is the default implementation of LayoutManager. You can use this class to create vertical or horizontal lists.
// Set RecyclerView layout to vertical layout
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
// Set RecyclerView layout to horizontal layout
LinearLayoutManager layoutManager= new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
Running the program, we see the following effects:
We find that unlike ListView, there are no splitting lines to make the list look ugly. Set a splitting line for RecyclerView, which we will explain in the next section.
Of course, there are some useful API s in Linearlayout Manager:
- findFirstVisibleItemPosition() Returns the position of the first visible Item currently
- findFirstCompletelyVisibleItemPosition() returns the position of the first fully visible Item currently in use.
- findLastVisibleItemPosition() Returns the position of the last visible Item currently
- findLastCompletelyVisibleItemPosition() Returns the position of the last fully visible Item currently in use.
3.3.2 GridLayoutManager
There are two construction methods:
/**
* Creates a vertical GridLayoutManager
*
* @param context Current context, will be used to access resources.
* @param spanCount Set the number of rows because the default is vertical
*/
public GridLayoutManager(Context context, int spanCount) {
super(context);
setSpanCount(spanCount);
}
/**
* @param context Current context, will be used to access resources.
* @param spanCount Set the number of rows or columns according to direction
* @param orientation Layout direction HORIZONTAL or VERTICAL.
* @param reverseLayout Whether to reverse display When set to true, layouts from end to start.
*/
public GridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
setSpanCount(spanCount);
}
We set it as follows:
// Set the table layout for the vertical four columns
GridLayoutManager layoutManager = new GridLayoutManager(this,4,GridLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(layoutManager);
// Set up a horizontal three-row table layout
GridLayoutManager layoutManager = new GridLayoutManager(this,3,GridLayoutManager.HORIZONTAL,false);
recyclerView.setLayoutManager(layoutManager);
3.3.3 StaggeredGridLayoutManager
Let's look at the way Staggered Grid Layout Manager is constructed. There's only one way
/**
* Creates a StaggeredGridLayoutManager with given parameters.
*
* @param spanCount Set the number of rows or columns. According to the direction, the vertical is the number of columns and the horizontal is the number of rows.
* @param orientation direction
*/
public StaggeredGridLayoutManager(int spanCount, int orientation) {}
So we set it up as follows:
// Set up vertical waterfall flow layout
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
We see no difference between the effect and GridLayout Manager, so let's make a little modification and you can see its power.
We add margin to the layout of each item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="@color/colorAccent">
<TextView
android:id="@+id/tv"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#fff"
/>
</LinearLayout>
Then we set a random height for our item in the onBindViewHolder method of the adapter:
//Please attach some codes and see the attachment for the rest.
private List<Integer> mHeights;
public RecyclerAdapter(Context context, List<String> mDatas) {
this.context = context;
this.mDatas = mDatas;
mHeights = new ArrayList<Integer>();
for (int i = 0; i < mDatas.size(); i++) {
mHeights.add((int) (100 + Math.random() * 300));
}
}
@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
lp.height = mHeights.get(position);
holder.tv.setLayoutParams(lp);
}
Running, we can see the effect, is it very dazzling!?
3.4 RecyclerView.ItemDecoration
By setting
recyclerView.addItemDecoration(new DividerDecoration(Context context, int orientation));
To change the offset between Items or decorate Items.
For example, if you add the following code after setting up the LinearlayoutManager above, the effect of the list will change:
// Set a partition line for the vertical display RecyclerView
recyclerView.addItemDecoration(new DividerItemDecoration(activity,DividerItemDecoration.VERTICAL));
// Set partitioning lines for horizontal display RecyclerView
recyclerView.addItemDecoration(new DividerItemDecoration(activity,DividerItemDecoration.HORIZONTAL));
Of course, you can also set up multiple ItemDecorations for RecyclerView. When the list is displayed, you will go through all ItemDecorations and call the drawing method inside to decorate the Item.
RecyclerView.ItemDecoration is an abstract class that can achieve offset or decoration between Items by rewriting the following three methods:
- The public void onDraw (Canvas c, Recycler View parent) decorative drawing is called before the Item entry is drawn, so this may be obscured by the content of the Item.
- The drawing of the public void onDrawOver (Canvas c, Recycler View parent) decoration is called after the Item entry is drawn, so the decoration will float over the Item.
- Public void getItem Offsets (Rect outRect, int itemPosition, Recycler View parent) are similar to padding or margin. LayoutManager calls this method at the measurement stage to calculate the correct size of each Item and set the offset.
Of course, if we use GridLayout Manager, the previous Divider ItemDecoration does not apply to partitioning lines, mainly because when drawing, such as horizontal lines, the values for each child are:
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
Because each Item has one line, that's OK. In GridLayoutManager, there are multiple child Items in a row, which are drawn many times, and in GridLayoutManager, if Item is the last column (there is no spacer on the right) or the last row (there is no dividing line at the bottom).
Following the above approach, we can customize a DividerGridItemDecoration. Because the code is too long, we give it in the annex. We set up Divider Grid ItemDecoration for GridLayout Manager, and the results are as follows:
3.5 RecyclerView.ItemAnimator
Item Animator can help Item achieve independent animation.
ItemAnimator triggers the following three events:
- A piece of data is inserted into the data set
- Remove a piece of data from a data set
- Change a piece of data in a data set
Fortunately, a Default Item Animator is implemented by default in Android, and we can add animation effects to Item by the following code:
recyclerView.setItemAnimator(new DefaultItemAnimator());
In previous versions, when the collection changed, we refreshed the list by calling. notifyDataSetChanged(), because this would trigger the redrawing of the list, so there would be no animation effect, so we needed to call some special methods prefixed with notifyItem*(), such as:
- public final void notifyItemInserted(int position) inserts Item into the specified location
- Public final void notify Item Remove (int position) removes the specified location Item
- Public final void notify ItemChanged (int position) updates the specified location Item
Next we use Default Item Animator to show the animation effect, and modify the code as follows:
Adding two buttons add and remove to Activity is responsible for dynamically inserting and removing item s
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
adapter.addData(1);
}
});
btnRemove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
adapter.removeData(2);
}
});
Add two methods to the Adapter:
public void addData(int position) {
mDatas.add(position, "Insert");
mHeights.add( (int) (100 + Math.random() * 300));
notifyItemInserted(position);
}
public void removeData(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
The results are as follows:
3.6 Listeners
Unfortunately, RecyclerView does not provide the following two Item click-listening events as ListView does.
- public void setOnItemClickListener(@Nullable OnItemClickListener listener) Item click event listener
- Public void setOnItemLong ClickListener
But that doesn't stop us. I can define two ways.
public interface OnItemClickLitener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
private OnItemClickLitener litener;
public void setLitener(OnItemClickLitener litener) {
this.litener = litener;
}
In the onBindViewHolder method, set listeners for controls that need to respond to click events:
// If a callback is set, it responds to the click event
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (litener != null) {
litener.onItemClick(v, position);
}
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (litener != null) {
litener.onItemLongClick(v, position);
}
return false;
}
});
Set this method in Activity:
adapter.setLitener(new RecyclerAdapter.OnItemClickLitener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(activity,"The first"+position+"Item clicked",Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(activity,"The first"+position+"The item was pressed long.",Toast.LENGTH_SHORT).show();
}
});
The effect is as follows:
Source address: http://download.csdn.net/detail/u012771445/9885640
Author: shijiacheng
Links to the original text: http://shijiacheng.studio/2017/06/30/first-RecyclerView/
Copyright Statement: All articles in this blog are original articles except special statements. Please respect the results of labor, reprint and indicate the source!