基础使用 - 纵向滚动
添加依赖库
mytest1\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest1\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
mytest1\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
/>
<TextView
android:id="@+id/fruit_price_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:textSize="30sp"
/>
</LinearLayout>
创建Fruit实体类
mytest1\src\main\java\com\example\mytest1\MyFruit.java
public class MyFruit {
private String name;
private float price;
public MyFruit(String name, float price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
自定义适配器Adapter
mytest1\src\main\java\com\example\mytest1\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 适配器,继承自 RecyclerView.Adapter,泛型指定为MyFruitAdapter.MyViewHolder
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitPrice.setText(mFruit.getPrice()+"元");
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitPrice;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitPrice = itemView.findViewById(R.id.fruit_price_tv);
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("苹果" + i, (float) (1 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("香蕉" + i, (float) (2 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("橘子" + i, (float) (3 + 0.01 * i)));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象 ,即线性布局
LinearLayoutManager mManager = new LinearLayoutManager(this);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
}
}
效果
代码示例
地址:GitHub
横向滚动
添加依赖库
mytest2\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest2\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
mytest2\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?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:orientation="vertical"
android:layout_marginLeft="20dp"
android:background="#ff0"
>
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
/>
<TextView
android:id="@+id/fruit_price_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
/>
</LinearLayout>
创建Fruit实体类
mytest2\src\main\java\com\example\mytest2\MyFruit.java
public class MyFruit {
private String name;
private float price;
public MyFruit(String name, float price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
自定义适配器Adapter
mytest2\src\main\java\com\example\mytest2\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 适配器,继承自 RecyclerView.Adapter,泛型指定为MyFruitAdapter.MyViewHolder
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitPrice.setText(mFruit.getPrice()+"元");
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitPrice;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitPrice = itemView.findViewById(R.id.fruit_price_tv);
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("苹果" + i, (float) (1 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("香蕉" + i, (float) (2 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("橘子" + i, (float) (3 + 0.01 * i)));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象 ,即线性布局
LinearLayoutManager mManager = new LinearLayoutManager(this);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
}
}
效果
代码示例
地址:GitHub
瀑布流布局
添加依赖库
mytest2\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest3\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
mytest3\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="5dp"
android:background="#FF44FF"
>
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
/>
<TextView
android:id="@+id/fruit_content_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_gravity="left"
android:layout_marginTop="10dp"
/>
</LinearLayout>
创建Fruit实体类
mytest3\src\main\java\com\example\mytest3\MyFruit.java
public class MyFruit {
private String name;
private String content;
public MyFruit(String name, String content) {
this.name = name;
this.content = content;
}
public String getName() {
return name;
}
public String getContent() {
return content;
}
}
自定义适配器Adapter
mytest3\src\main\java\com\example\mytest3\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 适配器,继承自 RecyclerView.Adapter,泛型指定为MyFruitAdapter.MyViewHolder
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitContent.setText(mFruit.getContent());
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitContent;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitContent = itemView.findViewById(R.id.fruit_content_tv);
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 15; i++) {
StringBuilder builder = new StringBuilder();
for (int j = 0; j < new Random().nextInt(10) + 1; j++){
builder.append("苹果");
}
mFruitList.add(new MyFruit("苹果" + i, builder.toString()));
}
for (int i = 1; i <= 15; i++) {
StringBuilder builder = new StringBuilder();
for (int j = 0; j < new Random().nextInt(10) + 1; j++){
builder.append("香蕉");
}
mFruitList.add(new MyFruit("香蕉" + i, builder.toString()));
}
for (int i = 1; i <= 15; i++) {
StringBuilder builder = new StringBuilder();
for (int j = 0; j < new Random().nextInt(10) + 1; j++){
builder.append("橘子");
}
mFruitList.add(new MyFruit("橘子" + i, builder.toString()));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 StaggeredGridLayoutManager 实例
// int spanCount : 指定布局的列数
// int orientation : 指定布局排列的方向
StaggeredGridLayoutManager mManager = new
StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
}
}
效果
代码示例
地址:GitHub
点击事件
添加依赖库
mytest4\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest4\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
mytest4\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
/>
<TextView
android:id="@+id/fruit_price_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:textSize="30sp"
/>
</LinearLayout>
创建Fruit实体类
mytest4\src\main\java\com\example\mytest4\MyFruit.java
public class MyFruit {
private String name;
private float price;
public MyFruit(String name, float price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
自定义适配器Adapter
mytest4\src\main\java\com\example\mytest4\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 适配器,继承自 RecyclerView.Adapter,泛型指定为MyFruitAdapter.MyViewHolder
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitPrice.setText(mFruit.getPrice()+"元");
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitPrice;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitPrice = itemView.findViewById(R.id.fruit_price_tv);
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("苹果" + i, (float) (1 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("香蕉" + i, (float) (2 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("橘子" + i, (float) (3 + 0.01 * i)));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象 ,即线性布局
LinearLayoutManager mManager = new LinearLayoutManager(this);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
}
}
效果
代码示例
地址:GitHub
分割线1 - 在适配器 onCreateViewHolder 中设置
在 Adapter 的 onCreateViewHolder 方法中进行设置 margin,以达到分割线的效果。
添加依赖库
mytest5\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest5\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
/>
</LinearLayout>
mytest5\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#9D9D9D"
>
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="30sp"
android:gravity="center"
/>
<TextView
android:id="@+id/fruit_price_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingLeft="20dp"
android:textSize="30sp"
android:gravity="center"
/>
</LinearLayout>
创建Fruit实体类
mytest5\src\main\java\com\example\mytest5\MyFruit.java
public class MyFruit {
private String name;
private float price;
public MyFruit(String name, float price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
自定义适配器Adapter
mytest5\src\main\java\com\example\mytest5\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 继承自 RecyclerView.Adapter
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
// ************ 设置分割线 使用margin的方式 ***************
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
layoutParams.topMargin = 1;
view.setLayoutParams(layoutParams);
// *****************************************************
// 创建自定义 viewHolder 实例
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitPrice.setText(mFruit.getPrice()+"元");
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitPrice;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitPrice = itemView.findViewById(R.id.fruit_price_tv);
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("苹果" + i, (float) (1 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("香蕉" + i, (float) (2 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("橘子" + i, (float) (3 + 0.01 * i)));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象 ,即线性布局
LinearLayoutManager mManager = new LinearLayoutManager(this);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
}
}
效果
代码示例
地址:GitHub
分割线2 - 在 ItemDecoration 中 getItemOffsets 设置 rect
在自定义 ItemDecoration 中,在 getItemOffsets 方法中 设置 rect,设置后,会露出底色,就是背景色,颜色也就取决于背景色了。
添加依赖库
mytest6\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest6\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
/>
</LinearLayout>
mytest6\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#9D9D9D"
>
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="30sp"
android:gravity="center"
/>
<TextView
android:id="@+id/fruit_price_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingLeft="20dp"
android:textSize="30sp"
android:gravity="center"
/>
</LinearLayout>
创建Fruit实体类
mytest6\src\main\java\com\example\mytest6\MyFruit.java
public class MyFruit {
private String name;
private float price;
public MyFruit(String name, float price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
自定义适配器Adapter
mytest6\src\main\java\com\example\mytest6\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 继承自 RecyclerView.Adapter
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
// 创建自定义 viewHolder 实例
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitPrice.setText(mFruit.getPrice()+"元");
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitPrice;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitPrice = itemView.findViewById(R.id.fruit_price_tv);
}
}
}
自定义ItemDecoration
import android.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
public class MyItemDecoration extends RecyclerView.ItemDecoration {
/**
* 获取Item的偏移量,结果保存在第一个参数outRect中
* @param outRect 是一个矩形,可以设置上下左右四个值。对应view在四个方向上的偏移量。默认是全为0的Rect
* 设置rect,会透漏出下面的背景色,看起来像是分割线,颜色取决于背景色
* @param view RecyclerView 中的 item
* @param parent RecyclerView本身
* @param state 状态
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
// 方式1
// outRect.top = 1;
// 方式2
outRect.set(0, 1, 0, 0);
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("苹果" + i, (float) (1 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("香蕉" + i, (float) (2 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("橘子" + i, (float) (3 + 0.01 * i)));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象 ,即线性布局
LinearLayoutManager mManager = new LinearLayoutManager(this);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
// 设置分割线
mRecyclerView.addItemDecoration(new MyItemDecoration());
}
}
效果
代码示例
地址:GitHub
分割线3 - getItemOffsets、onDraw、onDrawOver
在自定义 ItemDecoration 中,在 getItemOffsets 方法中 设置 rect,设置后,会露出底色,就是背景色,颜色也就取决于背景色了;
然后在 onDraw 方法 或 onDrawOver 方法中,再在 rect 区域再次绘制一个 rect。
添加依赖库
mytest7\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest7\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:padding="10dp"
/>
</LinearLayout>
mytest7\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#9D9D9D"
>
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="30sp"
android:gravity="center"
/>
<TextView
android:id="@+id/fruit_price_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingLeft="20dp"
android:textSize="30sp"
android:gravity="center"
/>
</LinearLayout>
创建Fruit实体类
mytest7\src\main\java\com\example\mytest7\MyFruit.java
public class MyFruit {
private String name;
private float price;
public MyFruit(String name, float price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
自定义适配器Adapter
mytest7\src\main\java\com\example\mytest7\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 继承自 RecyclerView.Adapter
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
// 创建自定义 viewHolder 实例
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitPrice.setText(mFruit.getPrice()+"元");
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitPrice;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitPrice = itemView.findViewById(R.id.fruit_price_tv);
}
}
}
自定义ItemDecoration
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class MyItemDecoration extends RecyclerView.ItemDecoration {
private int mDividerHeight;
/**
* 获取Item的偏移量,结果保存在第一个参数outRect中
* @param outRect 是一个矩形,可以设置上下左右四个值。对应view在四个方向上的偏移量。默认是全为0的Rect
* 设置rect,会透漏出下面的背景色,看起来像是分割线,颜色取决于背景色
* @param view RecyclerView 中的 item
* @param parent RecyclerView本身
* @param state 状态
*/
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
mDividerHeight = 2;
// 方式1
// outRect.top = mDividerHeight;
// 方式2
outRect.set(0, mDividerHeight, 0, 0);
}
/**
* 会在 绘制item之前调用,绘制的内容,会显示在 item 的底部,如果有重叠,会被 item 挡住
* @param c 为 Canvas
* @param parent RecyclerView本身
* @param state 状态
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
// Paint mPaint = new Paint();
// mPaint.setColor(Color.BLUE);
//
// for (int i = 0; i < parent.getChildCount(); i++) {
// View view = parent.getChildAt(i);
// int index = parent.getChildAdapterPosition(view);
//
// // 第一个 item 子项不绘制分割线
// if (index == 0) {
// continue;
// }
//
// float mLeft = parent.getPaddingLeft();
// float mTop = view.getTop() - mDividerHeight;
// float mRight = parent.getWidth() - parent.getPaddingRight();
// float mBottom = view.getTop();
//
// c.drawRect(mLeft, mTop, mRight, mBottom, mPaint);
// }
}
/**
* 会在 绘制item之后调用,绘制的内容,会显示在 item 的上部,如果有重叠,会把 item 挡住
* @param c 为 Canvas
* @param parent RecyclerView本身
* @param state 状态
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
Paint mPaint = new Paint();
mPaint.setColor(Color.RED);
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int index = parent.getChildAdapterPosition(view);
// 第一个 item 子项不绘制分割线
if (index == 0) {
continue;
}
float mLeft = parent.getPaddingLeft();
float mTop = view.getTop() - mDividerHeight;
float mRight = parent.getWidth() - parent.getPaddingRight();
float mBottom = view.getTop();
c.drawRect(mLeft, mTop, mRight, mBottom, mPaint);
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("苹果" + i, (float) (1 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("香蕉" + i, (float) (2 + 0.01 * i)));
}
for (int i = 1; i <= 10; i++) {
mFruitList.add(new MyFruit("橘子" + i, (float) (3 + 0.01 * i)));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象 ,即线性布局
LinearLayoutManager mManager = new LinearLayoutManager(this);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
// 设置分割线
mRecyclerView.addItemDecoration(new MyItemDecoration());
}
}
效果
代码示例
地址:GitHub
分割线4 - 实现每个分组都有一个头部分割线
添加依赖库
mytest8\build.gradle :
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
修改xml布局
mytest8\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:paddingTop="100dp"
/>
</LinearLayout>
mytest8\src\main\res\layout\fruit_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#9D9D9D"
>
<TextView
android:id="@+id/fruit_name_tv"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_weight="1"
android:textSize="20sp"
android:textColor="#90EE90"
android:gravity="center"
/>
<TextView
android:id="@+id/fruit_price_tv"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_weight="1"
android:paddingLeft="20dp"
android:textSize="20sp"
android:textColor="#90EE90"
android:gravity="center"
/>
</LinearLayout>
创建Fruit实体类
mytest8\src\main\java\com\example\mytest8\MyFruit.java
public class MyFruit {
private String group; // 分组
private String name; // 名称
private float price; // 价格
public MyFruit(String group, String name, float price) {
this.group = group;
this.name = name;
this.price = price;
}
public String getGroup() {
return group;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
}
自定义适配器Adapter
mytest8\src\main\java\com\example\mytest8\MyFruitAdapter.java :
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
// 继承自 RecyclerView.Adapter
public class MyFruitAdapter extends RecyclerView.Adapter<MyFruitAdapter.MyViewHolder> {
private List<MyFruit> mFruitList;
// 构造函数,list为需要展示的数据源
public MyFruitAdapter(List<MyFruit> list) {
this.mFruitList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item, parent, false);
// 创建自定义 viewHolder 实例
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyFruit mFruit = mFruitList.get(position);
holder.mFruitName.setText(mFruit.getName());
holder.mFruitPrice.setText(mFruit.getPrice()+"元");
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mFruitList.size();
}
// 内部类 继承自RecyclerView.ViewHolder
static class MyViewHolder extends RecyclerView.ViewHolder {
TextView mFruitName;
TextView mFruitPrice;
// 构造函数 通过传入的view,可以获取到 RecyclerView子项 的最外成布局
public MyViewHolder(View itemView) {
super(itemView);
mFruitName = itemView.findViewById(R.id.fruit_name_tv);
mFruitPrice = itemView.findViewById(R.id.fruit_price_tv);
}
}
/**
* 是否分组group的第一个
* @param position
*/
public boolean isGroupFirst(int position) {
// 如果 position 那说明就是第一个了
if (position == 0) {
return true;
} else {
// 当前 item 所在的分组名称
String currentGroupName = getGroupName(position);
// 前一个 item 所在的分组名称
String preGroupName = mFruitList.get(position - 1).getGroup();
// 如果当前item的分组 === 前一个item的分组,说明就不是第一个了
if (currentGroupName.equals(preGroupName)) {
return false;
} else {
return true;
}
}
}
/**
* 获取group名称
* @param position
* @return
*/
public String getGroupName(int position) {
return mFruitList.get(position).getGroup();
}
}
自定义ItemDecoration
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class MyItemDecoration extends RecyclerView.ItemDecoration {
private static final String TAG = "AAAAAAAAAA";
private int mHeadHeight;
Paint textPaint;
Rect textRect;
Paint headPaint;
public MyItemDecoration(Context context) {
mHeadHeight = dp2px(context, 100);
textPaint = new Paint();
textPaint.setTextSize(50);
textPaint.setColor(Color.WHITE);
textRect = new Rect();
headPaint = new Paint();
headPaint.setColor(Color.RED);
}
/**
* 获取Item的偏移量,结果保存在第一个参数outRect中
* @param outRect 是一个矩形,可以设置上下左右四个值。对应view在四个方向上的偏移量。默认是全为0的Rect
* 设置rect,会透漏出下面的背景色,看起来像是分割线,颜色取决于背景色
* @param view RecyclerView 中的 item
* @param parent RecyclerView本身
* @param state 状态
*/
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (parent.getAdapter() instanceof MyFruitAdapter) {
MyFruitAdapter adapter = (MyFruitAdapter) parent.getAdapter();
int position = parent.getChildAdapterPosition(view);
Log.d(TAG, "getItemOffsets position: " + position);
// 判断该 view 是否分组的第一个
if (adapter.isGroupFirst(position)) {
outRect.set(0, mHeadHeight, 0, 0);
} else {
outRect.set(0, 2, 0, 0);
}
}
}
/**
* 会在 绘制item之前调用,绘制的内容,会显示在 item 的底部,如果有重叠,会被 item 挡住
* @param c 为 Canvas
* @param parent RecyclerView本身
* @param state 状态
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if (parent.getAdapter() instanceof MyFruitAdapter) {
MyFruitAdapter adapter = (MyFruitAdapter) parent.getAdapter();
// 当前屏幕中可见的 item 数量
int childCount = parent.getChildCount();
int mLeft = parent.getPaddingLeft();
int mRight = parent.getWidth() - parent.getPaddingRight();
for (int i = 0; i < childCount; i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
Log.d(TAG, "onDraw position: " + position);
String groupName = adapter.getGroupName(position);
// itemView 的 top,减去 paddingTop,即上边界距离边缘的高度,如果大于头部区域的高度,才绘制分割线,否则不绘制
if (adapter.isGroupFirst(position) && view.getTop() - parent.getPaddingTop() >= mHeadHeight) {
c.drawRect( mLeft, view.getTop() - mHeadHeight, mRight, view.getTop(), headPaint);
textPaint.getTextBounds(groupName, 0, groupName.length(), textRect);
c.drawText(groupName, mLeft, view.getTop() - mHeadHeight/2 + textRect.height()/2, textPaint);
// itemView 的 top,减去 paddingTop,即上边界距离边缘的高度,如果大于头部区域的高度,才绘制分割线,否则不绘制
} else if (view.getTop() - parent.getPaddingTop() >= mHeadHeight) {
c.drawRect( mLeft, view.getTop() - 2, mRight, view.getTop(), headPaint);
}
}
}
}
/**
* 会在 绘制item之后调用,绘制的内容,会显示在 item 的上部,如果有重叠,会把 item 挡住
* @param c 为 Canvas
* @param parent RecyclerView本身
* @param state 状态
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
if (parent.getAdapter() instanceof MyFruitAdapter) {
MyFruitAdapter adapter = (MyFruitAdapter) parent.getAdapter();
// 返回可见区域的第一个 item 的 position
int position = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();
// 获取对应 position 的 itemView
View itemView = parent.findViewHolderForAdapterPosition(position).itemView;
int mLeft = parent.getPaddingLeft();
int mTop = parent.getPaddingTop();
int mRight = parent.getWidth() - parent.getPaddingRight();
// 当可见的第二个 itemView,是另外一个分组的头部,也就是把之前的头部给挤走
if (adapter.isGroupFirst(position+1)) {
// 当一个分组的最后一个 itemView,往上滑动的时候,如果它 小于 头部的高度,头部也要跟着滑动了,也就是挤走
// 头部分组的高度,会变化
int mTempHeight = Math.min(mHeadHeight, itemView.getBottom() - parent.getPaddingTop());
c.drawRect(mLeft, mTop, mRight, mTop + mTempHeight, headPaint);
String groupName = adapter.getGroupName(position);
textPaint.getTextBounds(groupName, 0, groupName.length(), textRect);
// 禁止文字在 padding 区域显示
c.clipRect(mLeft, mTop, mRight, mTop + mTempHeight);
// 绘制文字,有上移的效果
c.drawText(groupName, mLeft, mTop + mTempHeight - mHeadHeight/2 + textRect.height()/2, textPaint);
} else {
c.drawRect(mLeft, mTop, mRight, mTop + mHeadHeight, headPaint);
String groupName = adapter.getGroupName(position);
textPaint.getTextBounds(groupName, 0, groupName.length(), textRect);
c.drawText(groupName, mLeft, mTop + mHeadHeight/2 + textRect.height()/2, textPaint);
}
}
}
// dp 转成 px
private int dp2px(Context context, float dpValue) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale * 0.5f);
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyFruit> mFruitList = new ArrayList<>();
for (int i = 1; i <= 20; i++) {
mFruitList.add(new MyFruit("苹果", "苹果" + i, (float) (1 + 0.01 * i)));
}
for (int i = 1; i <= 20; i++) {
mFruitList.add(new MyFruit("香蕉", "香蕉" + i, (float) (2 + 0.01 * i)));
}
for (int i = 1; i <= 20; i++) {
mFruitList.add(new MyFruit("橘子", "橘子" + i, (float) (3 + 0.01 * i)));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象 ,即线性布局
LinearLayoutManager mManager = new LinearLayoutManager(this);
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyFruitAdapter mAdapter = new MyFruitAdapter(mFruitList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
// 设置分割线
mRecyclerView.addItemDecoration(new MyItemDecoration(this));
}
}
效果
代码示例
地址:GitHub
自定义LayoutManager
添加依赖库
mytest9\build.gradle :
dependencies {
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
修改xml布局
mytest9\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
mytest9\src\main\res\layout\pic_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="260dp"
android:layout_height="360dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:foreground="?android:attr/selectableItemBackground"
app:cardBackgroundColor="@color/teal_200">
<ImageView
android:id="@+id/pic_id_iv"
android:layout_width="200dp"
android:layout_height="300dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/pic_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="310dp"
android:paddingTop="10dp"
android:text="name"/>
<TextView
android:id="@+id/pic_position_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:layout_margin="3dp"
android:textColor="@android:color/white"
android:text="1/10"
/>
</androidx.cardview.widget.CardView>
创建MyPicBean实体类
mytest9\src\main\java\com\example\mytest9\MyPicBean.java
public class MyPicBean {
// 图片资源
private int pic_id;
// 图片名称描述
private String pic_name;
// 图片位置索引
private int pic_position;
public MyPicBean(int pic_id, String pic_name, int pic_position) {
this.pic_id = pic_id;
this.pic_name = pic_name;
this.pic_position = pic_position;
}
public int getPic_id() {
return pic_id;
}
public void setPic_id(int pic_id) {
this.pic_id = pic_id;
}
public String getPic_name() {
return pic_name;
}
public void setPic_name(String pic_name) {
this.pic_name = pic_name;
}
public int getPic_position() {
return pic_position;
}
public void setPic_position(int pic_position) {
this.pic_position = pic_position;
}
}
自定义适配器Adapter
mytest9\src\main\java\com\example\mytest9\MyPicAdapter.java :
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;
public class MyPicAdapter extends RecyclerView.Adapter<MyPicAdapter.MyViewHolder> {
private List<MyPicBean> mPicBeanList;
Context context;
// 构造函数,list为需要展示的数据源
public MyPicAdapter(Context context, List<MyPicBean> list) {
this.context = context;
this.mPicBeanList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.pic_item, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyPicBean mPicBean = mPicBeanList.get(position);
int mTotal = mPicBeanList == null ? 0 : mPicBeanList.size();
Glide.with(context).load(mPicBean.getPic_id()).into(holder.pic_id_iv);
holder.pic_name_tv.setText(mPicBean.getPic_name());
holder.pic_position_tv.setText(mPicBean.getPic_position()+"/" + mTotal);
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mPicBeanList == null ? 0 : mPicBeanList.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
ImageView pic_id_iv;
TextView pic_name_tv;
TextView pic_position_tv;
public MyViewHolder(View itemView) {
super(itemView);
pic_id_iv = itemView.findViewById(R.id.pic_id_iv);
pic_name_tv = itemView.findViewById(R.id.pic_name_tv);
pic_position_tv = itemView.findViewById(R.id.pic_position_tv);
}
}
}
自定义LayoutManager
mytest9\src\main\java\com\example\mytest9\MyLayoutManager.java :
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
public class MyLayoutManager extends RecyclerView.LayoutManager {
private static final String TAG = "AAAAAAA";
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
int itemCount = getItemCount();
Log.d(TAG, "itemCount: " +itemCount);
for (int i=0; i < itemCount; i++) {
View view = recycler.getViewForPosition(i);
addView(view);
measureChildWithMargins(view, 0, 0);
int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
layoutDecoratedWithMargins(view,
widthSpace/2,
heightSpace/2,
widthSpace/2 + getDecoratedMeasuredWidth(view),
heightSpace/2 + getDecoratedMeasuredHeight(view)
);
// X、Y轴进行平移
view.setTranslationY(10 * (itemCount -i));
view.setTranslationX(10 * (itemCount -i));
}
}
}
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyPicBean> mPicList = new ArrayList<>();
for (int i = 1; i <= 9; i++) {
mPicList.add(new MyPicBean(R.drawable.ic_launcher_background, "图" + i, i));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象
// LinearLayoutManager mManager = new LinearLayoutManager(this);
MyLayoutManager mManager = new MyLayoutManager();
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyPicAdapter mAdapter = new MyPicAdapter(this, mPicList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
}
}
效果
代码示例
地址:GitHub
自定义ItemTouchHelper.SimpleCallback
添加依赖库
mytest10\build.gradle :
dependencies {
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
修改xml布局
mytest10\src\main\res\layout\activity_main.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/test_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
mytest10\src\main\res\layout\pic_item.xml :
这个是 RecyclerView 的子项布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="260dp"
android:layout_height="360dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:foreground="?android:attr/selectableItemBackground"
app:cardBackgroundColor="@color/teal_200"
android:clickable="true"
>
<ImageView
android:id="@+id/pic_id_iv"
android:layout_width="200dp"
android:layout_height="300dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/pic_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="310dp"
android:paddingTop="10dp"
android:text="name"/>
<TextView
android:id="@+id/pic_position_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:paddingRight="20dp"
android:paddingBottom="20dp"
android:layout_margin="3dp"
android:textColor="@android:color/white"
android:text="1/10"
/>
</androidx.cardview.widget.CardView>
创建MyPicBean实体类
mytest10\src\main\java\com\example\mytest10\MyPicBean.java
public class MyPicBean {
// 图片资源
private int pic_id;
// 图片名称描述
private String pic_name;
// 图片位置索引
private int pic_position;
public MyPicBean(int pic_id, String pic_name, int pic_position) {
this.pic_id = pic_id;
this.pic_name = pic_name;
this.pic_position = pic_position;
}
public int getPic_id() {
return pic_id;
}
public void setPic_id(int pic_id) {
this.pic_id = pic_id;
}
public String getPic_name() {
return pic_name;
}
public void setPic_name(String pic_name) {
this.pic_name = pic_name;
}
public int getPic_position() {
return pic_position;
}
public void setPic_position(int pic_position) {
this.pic_position = pic_position;
}
}
自定义适配器Adapter
mytest10\src\main\java\com\example\mytest10\MyPicAdapter.java :
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.List;
public class MyPicAdapter extends RecyclerView.Adapter<MyPicAdapter.MyViewHolder> {
private List<MyPicBean> mPicBeanList;
Context context;
// 构造函数,list为需要展示的数据源
public MyPicAdapter(Context context, List<MyPicBean> list) {
this.context = context;
this.mPicBeanList = list;
}
// 用于创建 ViewHolder 实例
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.pic_item, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
// 对 RecyclerView子项 的数据进行赋值,会在每个子项被滚到到屏幕内的时候执行
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MyPicBean mPicBean = mPicBeanList.get(position);
int mTotal = mPicBeanList == null ? 0 : mPicBeanList.size();
Glide.with(context).load(mPicBean.getPic_id()).into(holder.pic_id_iv);
holder.pic_name_tv.setText(mPicBean.getPic_name());
holder.pic_position_tv.setText(mPicBean.getPic_position()+"/" + mTotal);
}
// 告诉 RecyclerView 一共有多少个子项,返回数据长度即可
@Override
public int getItemCount() {
return mPicBeanList == null ? 0 : mPicBeanList.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
ImageView pic_id_iv;
TextView pic_name_tv;
TextView pic_position_tv;
public MyViewHolder(View itemView) {
super(itemView);
pic_id_iv = itemView.findViewById(R.id.pic_id_iv);
pic_name_tv = itemView.findViewById(R.id.pic_name_tv);
pic_position_tv = itemView.findViewById(R.id.pic_position_tv);
}
}
}
自定义LayoutManager
mytest10\src\main\java\com\example\mytest10\MyLayoutManager.java :
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
public class MyLayoutManager extends RecyclerView.LayoutManager {
private static final String TAG = "AAAAAAA";
// 显示的item个数
public static final int showCount = 4;
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
int itemCount = getItemCount();
Log.d(TAG, "itemCount: " +itemCount); // 9
// 当前底部item 的 position
int bottomPosition;
// 如果item个数 小于 需要展示的个数,那就全部展示
if (itemCount < showCount) {
bottomPosition = 0;
} else {
bottomPosition = itemCount - showCount; // 5
}
for (int i=bottomPosition; i < itemCount; i++) {
View view = recycler.getViewForPosition(i);
addView(view);
measureChildWithMargins(view, 0, 0);
int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
layoutDecoratedWithMargins(view,
widthSpace/2,
heightSpace/2,
widthSpace/2 + getDecoratedMeasuredWidth(view),
heightSpace/2 + getDecoratedMeasuredHeight(view)
);
// 从下往上
int level = itemCount - i - 1; // 3
if (level > 0) {
// bottom 和 上面的一个偏移一样,即position 5 和 position 6,一样的
if (level < showCount - 1) {
// X、Y轴进行平移
view.setTranslationY(40 * level);
view.setTranslationX(40 * level);
} else {
// X、Y轴进行平移 最下面的跟它上面的一样
view.setTranslationY(40 * (level-1));
view.setTranslationX(40 * (level-1));
}
}
}
}
}
自定义ItemTouchHelper.SimpleCallback
mytest10\src\main\java\com\example\mytest10\MyItemTouchHelperCallback.java
import android.graphics.Canvas;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class MyItemTouchHelperCallback extends ItemTouchHelper.SimpleCallback {
private static final String TAG = "AAAAAA";
private RecyclerView recyclerView;
private MyPicAdapter adapter;
private List<MyPicBean> mDatas;
// public MyItemTouchHelperCallback(int dragDirs, int swipeDirs) {
// super(dragDirs, swipeDirs);
// }
public MyItemTouchHelperCallback(RecyclerView recyclerView, MyPicAdapter adapter, List<MyPicBean> mDatas) {
// 设置方向,拖拽、滑动,15为ox1111,即上下左右
super(0, 15);
this.recyclerView = recyclerView;
this.adapter = adapter;
this.mDatas = mDatas;
}
// drag用的
@Override
public boolean onMove(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull RecyclerView.ViewHolder target) {
return false;
}
// 滑动结束后的操作,滑动上面的item,再添加到下面
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
MyPicBean picBean = mDatas.remove(viewHolder.getLayoutPosition());
mDatas.add(0, picBean);
adapter.notifyDataSetChanged();
Log.d(TAG, "notifyDataSetChanged: ");
}
// 回弹时间
@Override
public long getAnimationDuration(@NonNull RecyclerView recyclerView,
int animationType, float animateDx, float animateDy) {
// return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
return 1000;
}
// 回弹距离
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
// return super.getSwipeThreshold(viewHolder);
return 0.2f;
}
// 绘制
@Override
public void onChildDraw(@NonNull Canvas c,
@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
double maxDistance = recyclerView.getWidth() * 0.5f;
// 根据x和y,求三角行的另外一个边长,即移动的直线距离
double distance = Math.sqrt(dX * dX + dY * dY);
// 放大系数
double fraction = distance / maxDistance;
if (fraction > 1) {
fraction = 1;
}
int itemCount = recyclerView.getChildCount(); // 4
for (int i = 0; i < itemCount; i++) {
View view = recyclerView.getChildAt(i);
int level = itemCount - i - 1;
if (level > 0) { // 最下面一张不偏移
if (level < MyLayoutManager.showCount -1) { // 最上面一张不管它
view.setTranslationY((float) (40 * (level - fraction)));
view.setTranslationX((float) (40 * (level - fraction)));
}
}
}
}
}
MainActivity.java
import android.os.Bundle;
import android.view.Window;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
List<MyPicBean> mPicList = new ArrayList<>();
for (int i = 1; i <= 9; i++) {
mPicList.add(new MyPicBean(R.drawable.ic_launcher_background, "图" + i, i));
}
// 获取到 RecyclerView 实例
RecyclerView mRecyclerView = findViewById(R.id.test_rv);
// 创建 LinearLayoutManager 对象
// LinearLayoutManager mManager = new LinearLayoutManager(this);
MyLayoutManager mManager = new MyLayoutManager();
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
// 创建自定义的 Adapter 实例
MyPicAdapter mAdapter = new MyPicAdapter(this, mPicList);
// 设置适配器
mRecyclerView.setAdapter(mAdapter);
// 创建 ItemTouchHelper
ItemTouchHelper.Callback callback = new MyItemTouchHelperCallback(
mRecyclerView, mAdapter, mPicList);
ItemTouchHelper helper = new ItemTouchHelper(callback);
helper.attachToRecyclerView(mRecyclerView);
}
}
效果
代码示例
地址:GitHub
ItemDecoration分析
ItemDecoration 可以用作设置分割线等效果;
当自定义 ItemDecoration 时,需要继承自 RecyclerView.ItemDecoration,根据需要重写方法 getItemOffsets、onDraw、onDrawOver。
getItemOffsets 方法,获取 Item 的偏移量,结果保存在第一个参数outRect中;
它仅仅获取屏幕内的 item;
/**
* 获取Item的偏移量,结果保存在第一个参数outRect中
* @param outRect 是一个矩形,可以设置上下左右四个值。对应view在四个方向上的偏移量。默认是全为0的Rect
* 设置rect,会透漏出下面的背景色,看起来像是分割线,颜色取决于背景色
* @param view RecyclerView 中的 item
* @param parent RecyclerView本身
* @param state 状态
*/
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
onDraw 方法,进行绘制,是在 item 之前进行绘制,也就是会被 item 给挡住。
/**
* 会在 绘制item之前调用,绘制的内容,会显示在 item 的底部,如果有重叠,会被 item 挡住
* @param c 为 Canvas
* @param parent RecyclerView本身
* @param state 状态
*/
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
onDrawOver 方法,也是进行绘制,是在 item 之后进行绘制,也就是会把 item 给挡住。
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
RecyclerView的方法
RecyclerView.setLayoutManager
设置 RecyclerView 使用的 LayoutManager
// 创建 LinearLayoutManager 对象
LinearLayoutManager mManager = new LinearLayoutManager(this);
mManager.setOrientation(LinearLayoutManager.HORIZONTAL); // 横向布局
// LayoutManager 用于指定 RecyclerView 的布局方式
// 将 LinearLayoutManager 设置到 RecyclerView 中,即设置线性布局
mRecyclerView.setLayoutManager(mManager);
RecyclerView.getLayoutManager()
获取 RecyclerView 之前设置的 LayoutManager,比如之前设置的 LinearLayoutManager
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
RecyclerView.getAdapter()
获取设置的适配器;
if (recyclerView.getAdapter() instanceof MyFruitAdapter) {
for (int i = 0; i < recyclerView.getChildCount(); i++) {
View view = recyclerView.getChildAt(i);
int index = recyclerView.getChildAdapterPosition(view);
}
}
RecyclerView.getChildCount()
获取子 item的个数,可见的 item 数量,并不一定是所有的 item 。
RecyclerView.getChildAt()
获取第 index 个子view
if (recyclerView.getAdapter() instanceof MyFruitAdapter) {
for (int i = 0; i < recyclerView.getChildCount(); i++) {
View view = recyclerView.getChildAt(i);
int index = recyclerView.getChildAdapterPosition(view);
}
}
RecyclerView.getChildAdapterPosition()
获取 item 在 adapter 中的位置
if (recyclerView.getAdapter() instanceof MyFruitAdapter) {
for (int i = 0; i < recyclerView.getChildCount(); i++) {
View view = recyclerView.getChildAt(i);
int index = recyclerView.getChildAdapterPosition(view);
}
}
RecyclerView.findViewHolderForAdapterPosition
获取 item 对应 position 位置,所属于的 ViewHolder
// 返回可见区域的第一个 item 的 position
int position = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
// 获取 item 对应 position 位置,所属于的 ViewHolder
RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(position);
// 获取 itemView
View itemView = viewHolder.itemView;
LinearLayoutManager 的方法
LinearLayoutManager.findFirstVisibleItemPosition
返回可见区域的第一个 item 的 position
int position = ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();