Android RecyclerView使用详解
来源:互联网 发布:剑网三光头捏脸数据 编辑:程序博客网 时间:2024/05/16 19:32
RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,RecyclerView与ListView的原理是类似的:都是仅仅维护少量的View并且可以展示大量的数据集,但是,RecyclerView提供了插拔式的体验,高度的解耦,十分的灵活 ,通过它提供的LayoutManager,ItemDecoration,ItemAnimator可以实现令ListView可望不可即的效果。
RecyclerView用以下两种方式简化了数据的展示和处理:
- 使用LayoutManager来确定每一个item的排列方式。
- 使用ItemAnimator来控制Item的增删动画。
- 使用ItemDecoration来控制Item的间隔。
先来看看实现的效果:
下面就来详解RecyclerView 的使用,以下给出了实现此效果的全部代码:
1,添加依赖:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.+' compile 'com.android.support:recyclerview-v7:23.2.1'}
<?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="com.example.recycleviewtest.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent" /></RelativeLayout>
3,和ListView相同,RecyclerView 也需要一个适配器,需要说明的是,RecyclerView 并没有提供点击和长按事件监听的API,所以需要自己来实现,这里我在适配器中通过定义接口,然后回调接口的方式来实现点击和长按事件的监听。代码中有详细注解:
package com.example.recycleviewtest;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;/** * Created by Administrator on 2016/10/6. * RecycleView对应的适配器 * 要求必须实现ViewHolder类,用于缓存控件 */public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> { //通过构造方法把数据传递过来 protected ArrayList<String>mData; protected LayoutInflater inflater; public MyAdapter(Context context,ArrayList<String> mData) { this.mData = mData; this.inflater = LayoutInflater.from(context); } //定义一个接口,响应点击事件 protected OnItemClickListener mOnItemClickListener; protected interface OnItemClickListener{ //点击事件的回调 void setOnItemClick(View view,int position); void setOnLongItemClick(View view,int position); } public void setmOnItemClickListener(OnItemClickListener listener) { this.mOnItemClickListener = listener; } /** * 渲染布局 */ @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = inflater.inflate(R.layout.item, parent, false); return new MyViewHolder(itemView); } /** * 将数据绑定到ViewHolder */ @Override public void onBindViewHolder(MyViewHolder holder, final int position) { //将传递过来的数据设置给holder中的控件 holder.mTextView.setText(mData.get(position)); //初始化点击事件 initClick(holder,position); } protected void initClick(MyViewHolder holder, final int position) { //单击事件的回调 holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // mOnItemClickListener是在MainActivity调用之后传过来的, // 如果不为空,说明被调用了,把当前的position回调给MainActivity if (mOnItemClickListener != null){ mOnItemClickListener.setOnItemClick(v,position); } } }); //长按事件的回调 holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (mOnItemClickListener != null){ mOnItemClickListener.setOnLongItemClick(v,position); } return true; //注意:一定要返回true,这样可以消费事件,让点击事件不再生效 } }); } /** * 返回条目数 */ @Override public int getItemCount() { return mData.size(); } /** * 用于缓存条目数据的Holder类 * RcycleView要求必须实现此类 */ public class MyViewHolder extends RecyclerView.ViewHolder{ //参数itemView即为要缓存的条目布局 TextView mTextView; public MyViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(R.id.tv); } }}
RecyclerView.LayoutManager是一个抽象类,系统提供了3个实现类:
① LinearLayoutManager 现行管理器,支持横向、纵向。默认为纵向。
② GridLayoutManager 网格布局管理器,支持横向、纵向。默认为纵向。
③ StaggeredGridLayoutManager 瀑布就式布局管理器,支持横向、纵向。默认为纵向。
package com.example.recycleviewtest;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.support.v7.widget.DefaultItemAnimator;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.StaggeredGridLayoutManager;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Toast;import java.util.ArrayList;public class MainActivity extends AppCompatActivity { private RecyclerView mRecycleView; private ArrayList<String>mData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //1.获取RecyclerView控件 mRecycleView = (RecyclerView) findViewById(R.id.rv); //2.获取数据 initData(); //3.设置适配器 MyAdapter adapter = new MyAdapter(this,mData); //4.给RecyclerView设置布局容器 // 4.1 线性布局// mRecycleView.setLayoutManager(new LinearLayoutManager(this)); // 4.2 宫格布局(GridView) (设置为默认布局) mRecycleView.setLayoutManager(new GridLayoutManager(this,2)); // 4.3 瀑布流布局// mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)); //5.给RecyclerView设置适配器 mRecycleView.setAdapter(adapter); //6.给RecyclerView添加分割线// mRecycleView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); //7.给RecyclerView设置动画 mRecycleView.setItemAnimator(new DefaultItemAnimator()); //8.给适配器设置点击事件 adapter.setmOnItemClickListener(new MyAdapter.OnItemClickListener() { @Override public void setOnItemClick(View view, int position) { Toast.makeText(MainActivity.this,"点击了"+position+"条目",Toast.LENGTH_SHORT).show(); } @Override public void setOnLongItemClick(View view, int position) { Toast.makeText(MainActivity.this,"长按了"+position+"条目",Toast.LENGTH_SHORT).show(); } }); } /** * 初始化数据 */ private void initData() { mData = new ArrayList<>(); for (int i = 'A'; i <= 'z'; i++) { mData.add(String.valueOf((char)i)); } } /** * 创建选择菜单 * 加载自定义的菜单 * @param menu Interface for managing the items in a menu. * @return */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu,menu); return true; //消费事件,处理自己的业务 } /** * 菜单选择项 * 判断选择了哪个菜单项,做相应的业务 * @param item 选中的菜单项 * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); switch (itemId){ //根据选中菜单项的id来显示不同的布局 case R.id.listView: //线性布局 mRecycleView.setLayoutManager(new LinearLayoutManager(this)); break; case R.id.gridView: //宫格布局 mRecycleView.setLayoutManager(new GridLayoutManager(this,2)); break; case R.id.horizontalStaggerGridView: //水平瀑布流宫格布局 mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.HORIZONTAL)); break; case R.id.staggerGridView: //垂直瀑布流宫格布局 Intent intent = new Intent(MainActivity.this,StaggerActivity.class); startActivity(intent); break; } return true; }}
5,把不同的布局切换以菜单的形式来展示,这样界面看起来更加的简洁,对应的菜单文件res---->menu---->menu.xml:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <item android:id="@+id/listView" android:orderInCategory="100" android:showAsAction="never" android:title="ListView" tools:ignore="AppCompatResource"/> <item android:id="@+id/gridView" android:orderInCategory="100" android:showAsAction="never" android:title="GridView" tools:ignore="AppCompatResource"/> <item android:id="@+id/horizontalStaggerGridView" android:orderInCategory="100" android:showAsAction="never" android:title="HorizontalStaggerGridView" tools:ignore="AppCompatResource"/> <item android:id="@+id/staggerGridView" android:orderInCategory="100" android:showAsAction="never" android:title="StaggerGridView" tools:ignore="AppCompatResource"/></menu>
6,适配器中条目布局对应的布局文件item.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:background="#55aa00ff" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp"> <TextView android:id="@+id/tv" android:layout_width="60dp" android:layout_height="40dp" android:textSize="20sp" android:gravity="center"/></LinearLayout>
7,RecyclerView虽然很强大,但我感觉有两个让我们开发者很不爽的地方,一是没有点击和长按监听事件,二是没有提供分割线的API,所以如果我们想设置分割线的话需要自定义,我在代码中设置分割线的代码注释掉了,而是使用布局文件来给每个Item设置间距,下面是官方提供的分割线的demo:
package com.example.recycleviewtest;/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */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.util.Log;import android.view.View;/** * This class is from the v7 samples of the Android SDK. It's not by me! * <p/> * See the license above for details. */public class DividerItemDecoration extends RecyclerView.ItemDecoration{//分割线的图片属性,系统图片private static final int[] ATTRS = new int[] { android.R.attr.listDivider };//水平排列public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;//垂直排列public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;private Drawable mDivider;private int mOrientation;public DividerItemDecoration(Context context, int orientation){//自定义属性样式final TypedArray a = context.obtainStyledAttributes(ATTRS);mDivider = a.getDrawable(0);a.recycle();setOrientation(orientation);}/** * 设置排列方向 * @param orientation */public void setOrientation(int orientation){if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST){throw new IllegalArgumentException("invalid orientation");}mOrientation = orientation;}/** * 绘制分割线 * @param c * @param parent */@Overridepublic void onDraw(Canvas c, RecyclerView parent){ if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); }}/** * 画竖直方向的分割线 * @param c * @param parent */public 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; i++){final View child = parent.getChildAt(i);RecyclerView v = new RecyclerView(parent.getContext());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);}}/** * 画水平方向的分割线 * @param c * @param parent */public 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; 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);}}/** * 为分割线预留空间 * @param outRect * @param itemPosition * @param parent */@Overridepublic void getItemOffsets(Rect outRect, int itemPosition,RecyclerView parent){if (mOrientation == VERTICAL_LIST){//如果垂直排列,则预留每个条目的下方outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());} else{//如果水平排列,则预留每个条目的右方outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);}}}
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <!--gradient:设置矩形的渐变色 size:设置矩形的尺寸--> <gradient android:startColor="#ff0000" android:centerColor="#00ff00" android:endColor="#0000ff" android:type="linear"/> <size android:width="4dp" android:height="4dp"/></shape>
9,实现垂直瀑布流宫格布局效果时,需要设置每个条目的高度(或宽带)最好有差别,这里我的思路是:当选择垂直瀑布流宫格布局时,我跳转到另外一个StaggerActivity中,在StaggerActivity对应的适配器中来改变每个条目的高度。这个方案很笨拙,但容易理解,StaggerActivity对应的适配器代码:
package com.example.recycleviewtest;import android.content.Context;import android.view.ViewGroup;import java.util.ArrayList;/** * Created by Administrator on 2016/10/7. */public class StaggerAdapter extends MyAdapter { private ArrayList<Integer> mHeights; //瀑布流item的高度 public StaggerAdapter(Context context, ArrayList<String> mData) { super(context, mData); mHeights = new ArrayList<>(); for (int i = 0; i < mData.size(); i++) { mHeights.add((int) (Math.random()*300 + 100)); } } /* 在绑定数据时改变item的高度 */ @Override public void onBindViewHolder(MyViewHolder holder, int position) { //2.通过getLayoutParams拿到对应控件的属性,对其进行设置 ViewGroup.LayoutParams params = holder.mTextView.getLayoutParams(); //3.改变item的高度 params.height = mHeights.get(position); //1.通过setLayoutParams方法来设置控件的属性 holder.mTextView.setLayoutParams(params); //给控件设置内容 holder.mTextView.setText(mData.get(position)); //初始化监听事件 initClick(holder,position); }}
10,StaggerActivity其实和MainActivity的代码几乎相同,只是改变适配器和menu的条目选择后的跳转方向。
package com.example.recycleviewtest;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.DefaultItemAnimator;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.StaggeredGridLayoutManager;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Toast;import java.util.ArrayList;public class StaggerActivity extends AppCompatActivity { private RecyclerView mRecycleView; private ArrayList<String>mData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //1.获取RecyclerView控件 mRecycleView = (RecyclerView) findViewById(R.id.rv); //2.获取数据 initData(); //3.设置适配器 StaggerAdapter adapter = new StaggerAdapter(this,mData); //4.给RecyclerView设置布局容器 // 4.1 线性布局// mRecycleView.setLayoutManager(new LinearLayoutManager(this)); // 4.2 宫格布局(GridView)// mRecycleView.setLayoutManager(new GridLayoutManager(this,2)); // 4.3 瀑布流布局 mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)); //5.给RecyclerView设置适配器 mRecycleView.setAdapter(adapter); //6.给RecyclerView设置分割线// mRecycleView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); //7.给RecyclerView设置动画 mRecycleView.setItemAnimator(new DefaultItemAnimator()); //8.给适配器设置点击事件 adapter.setmOnItemClickListener(new MyAdapter.OnItemClickListener() { @Override public void setOnItemClick(View view, int position) { Toast.makeText(StaggerActivity.this,"点击了"+position+"条目",Toast.LENGTH_SHORT).show(); } @Override public void setOnLongItemClick(View view, int position) { Toast.makeText(StaggerActivity.this,"长按了"+position+"条目",Toast.LENGTH_SHORT).show(); } }); } /** * 初始化数据 */ private void initData() { mData = new ArrayList<>(); for (int i = 'A'; i <= 'z'; i++) { mData.add(String.valueOf((char)i)); } } /** * 创建选择菜单 * 加载自定义的菜单 * @param menu Interface for managing the items in a menu. * @return */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu,menu); return true; //消费事件,处理自己的业务 } /** * 菜单选择项 * 判断选择了哪个菜单项,做响应的业务 * @param item 选中的菜单项 * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); switch (itemId){ //根据选中菜单项的id来显示不同的布局 case R.id.listView: //线性布局 Intent intent = new Intent(StaggerActivity.this,MainActivity.class); startActivity(intent); break; case R.id.gridView: //宫格布局 Intent intent2 = new Intent(StaggerActivity.this,MainActivity.class); startActivity(intent2); break; case R.id.horizontalStaggerGridView: //水平瀑布流宫格布局 Intent intent3 = new Intent(StaggerActivity.this,MainActivity.class); startActivity(intent3); break; case R.id.staggerGridView: //垂直瀑布流宫格布局 mRecycleView.setLayoutManager(new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)); break; } return true; }}
2 0
- Android RecyclerView 使用详解
- Android RecyclerView使用详解
- Android RecyclerView使用详解
- Android RecyclerView使用详解
- Android RecyclerView使用详解
- Android RecyclerView使用详解
- Android RecyclerView使用详解一
- Android RecyclerView使用详解二
- Android RecyclerView使用详解三
- Android RecyclerView使用详解四
- android RecyclerView使用及详解
- Android RecyclerView 详解(五) RecyclerView多布局的使用
- Android RecyclerView使用详解(一)
- Android RecyclerView使用详解(二)
- Android RecyclerView使用详解(三)
- Android 中RecyclerView使用详解(一)
- android RecyclerView 瀑布流使用详解
- First RecyclerView (RecyclerView使用详解)
- HDU - 5927 Auxiliary Set (树形DP)
- hdu 4800 Josephina and RPG【dp】
- 《 Clean Code 》 读书笔记(一)
- PCB课程设计6.1(元器件封装库的创建:手动创建)
- 【3】 Android RecyclerView使用
- Android RecyclerView使用详解
- [ROS]Cartographer的初体验
- angular路由与ng-options/ng-include指令
- 2121数据结构实验之链表六:有序链表的建立
- 【Android】如何方便地将代码抛到主线程执行
- Windows下的Pycharm远程连接虚拟机中Centos下的Python环境
- runtime的使用总结
- 顺序表应用4-2:元素位置互换之逆置算法(数据改进)
- 习题8.18