您的位置:首页 > 移动开发 > Android开发

Android控件RecyclerView的基本用法

2017-05-17 20:20 375 查看
  RecyclerView是Android提供的一个功能强大的滚动控件,是增强版的ListView和GridView,不仅可以轻松实现和ListView相同的效果,还优化了ListView中存在的各种不足之处;目前Android官方更加推荐使用RecyclerView,本文介绍一下Android Studio中RecyclerView的基本用法。

  RecyclerView需要通过setLayoutManager()方法设置布局管理器,RecyclerView有三个默认布局管理器LinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManager,它们都支持横向和纵向排列以及反向滑动。如果想把RecyclerView改为横向滑动,可以通过调用:

layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 改变RecyclerView的方向


  RecyclerView是Android新增的控件,为了让RecyclerView在所有的Android版本上都可以使用,Android团队采取了将RecyclerView定义在support库中,所以,我们如果要使用RecyclerView这个控件,首先需要在项目中的build.gradle(Module:app)中添加相应的依赖库;

  打开build.gradle(Module:app)文件,在dependencies闭包中添加如下内容:

apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "neu.cn.myrecyclerview"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
testCompile 'junit:junit:4.12'
}


  添加过之后点击Sync Now进行同步,同步完后,接下来修改主布局activity_main.xml,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context="neu.cn.myrecyclerview.MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<Button
android:id="@+id/add_item"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Add Item"
android:textAllCaps="false" />

<Button
android:id="@+id/delete_item"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Delete Item"
android:textAllCaps="false" />

</LinearLayout>

<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</LinearLayout>


  在布局中加入RecyclerView控件,需要注意的是,由于RecyclerView并不是内置在系统SDK中的,所以需要把完整的包路径写出来;

  为RecyclerView新建一个适配器类FruitAdapter,并让其继承自RecyclerView.Adapter,并指定其泛型为FruitAdapter.MyViewHolder,MyViewHolder是FruitAdapter的内部类;如下:

package neu.cn.myrecyclerview;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;
import java.util.Random;

/**
* Created by neuHenry on 2017/6/1.
*/

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.MyViewHolder> {

private List<Fruit> mFruitList;

public FruitAdapter(List<Fruit> mFruitList) {
this.mFruitList = mFruitList;
}

@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
final MyViewHolder holder = new MyViewHolder(view);
holder.fruitView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(), "you clicked fruitView " + fruit.getImageName(), Toast.LENGTH_SHORT).show();
}
});
holder.fruitImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(), "you clicked fruitImage " + fruit.getImageName(), Toast.LENGTH_SHORT).show();
}
});
holder.fruitName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(), "you clicked fruitName " + fruit.getImageName(), Toast.LENGTH_SHORT).show();
}
});
return holder;
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageID());
holder.fruitName.setText(fruit.getImageName());
}

@Override
public int getItemCount() {
return mFruitList.size();
}

/**
* RecyclerView 中动态添加Item
* @param position
*/
public void addItem(int position) {
Random random = new Random(mFruitList.size());
int index = random.nextInt(mFruitList.size());
Fruit fruit = mFruitList.get(index);
mFruitList.add(fruit);
notifyItemInserted(position);
}

/**
* RecyclerView 中动态删除Item
* @param position
*/
public void deleteItem(int position) {
mFruitList.remove(position);
notifyItemRemoved(position);
}

class MyViewHolder extends RecyclerView.ViewHolder {
View fruitView;
ImageView fruitImage;
TextView fruitName;

public MyViewHolder(View view) {
super(view);
fruitView = view;
fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
fruitName = (TextView) view.findViewById(R.id.fruit_name);
}
}
}


fruit_item.xml的代码如下:

<?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"
android:layout_margin="5dp"
android:orientation="horizontal">

<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp" />

</LinearLayout>


Fruit.java的代码如下:

package neu.cn.myrecyclerview;

/**
* Created by neuHenry on 2017/6/1.
*/

public class Fruit {

private int imageID;
private String imageName;

public Fruit(int imageID, String imageName) {
this.imageID = imageID;
this.imageName = imageName;
}

public int getImageID() {
return imageID;
}

public String getImageName() {
return imageName;
}
}


修改MainActivity中的代码,如下:

package neu.cn.myrecyclerview;

import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
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.support.v7.widget.helper.ItemTouchHelper;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

// 水果数据列表,存放水果数据
private List<Fruit> fruitList = new ArrayList<>();
private RecyclerView recyclerView;
private FruitAdapter fruitAdapter;
// 处理RecyclerView中Item的滑动和拖拽
private ItemTouchHelper itemTouchHelper;
private WindowManager windowManager;

private Button addItem;
private Button deleteItem;
private int screenwidth;
private Boolean remove;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
fruitAdapter = new FruitAdapter(fruitList);
remove = false;
addItem = (Button) findViewById(R.id.add_item);
deleteItem = (Button) findViewById(R.id.delete_item);
windowManager = (WindowManager) MainActivity.this.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(outMetrics);
screenwidth = outMetrics.widthPixels; // 获取屏幕宽度
addItem.setOnClickListener(this);
deleteItem.setOnClickListener(this);
itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {

// 用于设置拖拽和滑动的方向
@Override
public int getMovementFlags(RecyclerView recyclerV
f01a
iew, RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0, swipeFlags = 0;
if (recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager || recyclerView.getLayoutManager() instanceof GridLayoutManager) {
// 瀑布流和网格布局有四个拖拽方向
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
} else if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
// 线性布局有两个拖拽方向
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
// 设置侧滑方向为从两个方向都可以
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
}
return makeMovementFlags(dragFlags, swipeFlags);
}

// 长摁Item拖拽时会回调这个方法
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
Collections.swap(fruitList, from, to); // 交换fruitList中数据的位置
fruitAdapter.notifyItemMoved(from, to); // 更新适配器中item的位置
return true;
}

// 处理滑动删除操作
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
fruitAdapter.deleteItem(viewHolder.getAdapterPosition());
fruitAdapter.notifyDataSetChanged();
}

@Override
public boolean isLongPressDragEnabled() {
return true; // 返回true则为所有Item都设置可以拖拽
}

// 当Item拖拽开始时调用
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
super.onSelectedChanged(viewHolder, actionState);
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
viewHolder.itemView.setElevation(100);
}
}
}

// 当Item拖拽完成时调用
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
viewHolder.itemView.setElevation(0);
}
}

// 当Item视图变化时调用
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {

viewHolder.itemView.scrollTo(-(int) dX, -(int) dY); // 根据Item的滑动偏移修改HorizontalScrollView的滚动
if (Math.abs(dX) > screenwidth / 5 && !remove && isCurrentlyActive) {
// 用户收滑动Item超过屏幕5分之1,标记为要删除
remove = true;
} else if (Math.abs(dX) < screenwidth / 5 && remove && !isCurrentlyActive) {
// 用户收滑动Item没有超过屏幕5分之1,标记为不删除
remove = false;
}
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE && remove == true && !isCurrentlyActive) {
// 当用户滑动Item超过屏幕5分之1,并且松手时,执行删除Item
if (viewHolder != null && viewHolder.getAdapterPosition() >= 0) {
fruitAdapter.deleteItem(viewHolder.getAdapterPosition());
remove = false;
}
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
});

recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
// 与RecyclView绑定
itemTouchHelper.attachToRecyclerView(recyclerView);
// 线性布局
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 改变RecyclerView的方向
// 网格布局
//        GridLayoutManager layoutManager = new GridLayoutManager(this, 3); // 第二个参数表示每行显示的个数
// 瀑布流布局
//        StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(fruitAdapter);
recyclerView.setItemAnimator(new DefaultItemAnimator()); // 设置Item加载或移除时的动画
}

/**
* 初始化水果数据列表
*/
private void initFruits() {
for (int i = 0; i < 2; i++) {
Fruit apple = new Fruit(R.drawable.apple_pic, getRandomName("Apple"));
fruitList.add(apple);
Fruit banana = new Fruit(R.drawable.banana_pic, getRandomName("Banana"));
fruitList.add(banana);
Fruit orange = new Fruit(R.drawable.orange_pic, getRandomName("Orange"));
fruitList.add(orange);
Fruit watermelon = new Fruit(R.drawable.watermelon_pic, getRandomName("Watermelon"));
fruitList.add(watermelon);
Fruit pear = new Fruit(R.drawable.pear_pic, getRandomName("Pear"));
fruitList.add(pear);
Fruit grape = new Fruit(R.drawable.grape_pic, getRandomName("Grape"));
fruitList.add(grape);
Fruit pineapple = new Fruit(R.drawable.pineapple_pic, getRandomName("Pineapple"));
fruitList.add(pineapple);
Fruit strawberry = new Fruit(R.drawable.strawberry_pic, getRandomName("Strawberry"));
fruitList.add(strawberry);
Fruit cherry = new Fruit(R.drawable.cherry_pic, getRandomName("Cherry"));
fruitList.add(cherry);
Fruit mango = new Fruit(R.drawable.mango_pic, getRandomName("Mango"));
fruitList.add(mango);
}
}

private String getRandomName(String name) {
StringBuffer buffer = new StringBuffer();
Random random = new Random(20);
int length = random.nextInt(20);
for (int i = 0; i < length; i++) {
buffer.append(name);
}
return buffer.toString();
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.add_item: // RecyclerView中添加Item
fruitAdapter.addItem(fruitList.size());
break;
case R.id.delete_item: // // RecyclerView中删除Item
fruitAdapter.deleteItem(fruitList.size() - 1);
break;
default:
break;
}
}
}


运行,效果如下:

 


1、修改代码,使的RecyclerView实现水平滚动效果,把fruit_item.xml中的元素改成垂直排列,修改布局的相关属性等,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:orientation="vertical">

<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>

<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp" />

</LinearLayout>


2、修改MainActivity的代码实现水平滚动,加入:

layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 改变RecyclerView的方向

效果如下:



3、修改MainActivity的代码实现网格布局,如下:

GridLayoutManager layoutManager = new GridLayoutManager(this, 3); // 第二个参数表示每行显示的个数

效果如下:



4、再次修改MainActivity的代码和fruit_item的代码,实现瀑布流布局,上面的MainActivity代码就是修改后的,瀑布流布局需要各个子项高度不一致才能看出来,图片大小都一样,为此只有在TextView中多加一些字啦!效果如下所示:



  RecyclerView不同于ListView的点击事件,RecyclerView不像ListView一样提供item的点击监听,所以需要我们自己实现给子项具体的View去注册点击事件。RecyclerView的item点击事件监听可以向我代码中为item的view设置监听,也可以在recyclerView.addOnItemTouchListener里去判断手势来实现。

  另外,代码后续实现了通过点击按钮动态的添加和删除RecyclerView中的Item子项,通过添加和删除可以更好的理解RecyclerView的三种布局管理器;



  ItemTouchHelper是一个处理RecyclerView的滑动删除和拖拽的辅助类,RecyclerView 的item拖拽移动和滑动删除就靠它来实现。ItemTouchHelper需要在RecyclerView初始化的时候调用

itemTouchHelper.attachToRecyclerView(recyclerView);


通过attachToRecyclerView与RecyclerView 绑定后生效,如果想要为Item设置拖拽和滑动时的响应动画效果,可以重写ItemTouchHelper的三个方法来实现:onSelectedChanged、clearView、onChildDraw,具体的实现见代码;

  文中代码地址:MyRecyclerView
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: