赞
踩
implementation 'androidx.recyclerview:recyclerview:1.1.0'
2.1、首先是两个布局文件
Activity 的布局文件
<?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="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
item 的布局文件
<?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">
<TextView
android:id="@+id/tvItem"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center" />
</LinearLayout>
2.2、Adapter 代码
public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> { private List<String> mList; private Context mContext; public HomeAdapter(Context mContext, List<String> mList) { this.mContext = mContext; this.mList = mList; } public void removeData(int position) { mList.remove(position); notifyDataSetChanged(); } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_recycler, parent, false); MyViewHolder holder = new MyViewHolder(itemView); return holder; } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { holder.tv.setText(mList.get(position)); } @Override public int getItemCount() { return mList.size(); } class MyViewHolder extends RecyclerView.ViewHolder { private TextView tv; public MyViewHolder(@NonNull View itemView) { super(itemView); tv = itemView.findViewById(R.id.tvItem); } } }
2.3、Activity 中的代码
public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView; private HomeAdapter mHomeAdapter; private List<String> mList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = this.findViewById(R.id.recyclerView); // 设置布局管理器 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); linearLayoutManager.setOrientation(RecyclerView.VERTICAL); mRecyclerView.setLayoutManager(linearLayoutManager); // 设置 item 增加和删除时的动画 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mList = getList(); mHomeAdapter = new HomeAdapter(this, mList); mRecyclerView.setAdapter(mHomeAdapter); } private List<String> getList() { List<String> list = new ArrayList<>(); for (int i = 0; i < 100; i++) { list.add(i + ""); } return list; } }
2.4、排列方向
垂直排列(默认): linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
水平排列: linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);
运行效果
参考博客:
RecyclerView之ItemDecoration由浅入深
RecyclerView 之 ItemDecoration 讲解及高级特性实践
正确使用RecyclerView分割线
3.1、默认分割线。
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, RecyclerView.VERTICAL));
效果图:
3.2、复制 DividerItemDecoration 的源码进行修改。参考 5.2 中示例
我们可以根据默认分割线的源码,继承 RecyclerView.ItemDecoration 来自定义分割线。里面核心的方法就是 onDraw 方法,它根据传进来的 orientation 来判断是绘制横向 item 的分割线还是纵向 item 的分割线。getItemOffsets 方法则用于设置 item 的 padding 属性。
1、自定义接口并提供回调方法
private OnItemClickListener mOnItemClickListener;
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.mOnItemClickListener = onItemClickListener;
}
2、Adapter 继承 View.OnClickListener 和 View.OnLongClickListener 并实现其中的方法。
3、OnBindViewHolder 方法中给 item 设置 tag。
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.itemView.setTag(position);
holder.tv.setText(mList.get(position));
}
4、监听 item 的点击事件并回调给我们自定义的监听。
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_recycler, parent, false);
MyViewHolder holder = new MyViewHolder(itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
return holder;
}
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(v, (int) v.getTag());
}
}
@Override
public boolean onLongClick(View v) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemLongClick(v, (int) v.getTag());
}
return false;
}
5、最后在 Activity 中进行监听
mHomeAdapter.setOnItemClickListener(new HomeAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条", Toast.LENGTH_SHORT).show(); } @Override public void onItemLongClick(View view, final int position) { new AlertDialog.Builder(MainActivity.this) .setTitle("确认删除吗?") .setNegativeButton("取消", null) .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mHomeAdapter.removeData(position); } }).show(); } });
长按时会弹出对话框,效果如下。
5.1、布局管理器
这里设置 4 列
GridLayoutManager gridLayoutManager = new GridLayoutManager(this,4);
mRecyclerView.setLayoutManager(gridLayoutManager);
或者用瀑布流布局管理器
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(staggeredGridLayoutManager);
注意:StaggeredGridLayoutManager.VERTICAL 的情况下,4 是列数,表示只有 4 列。改为 StaggeredGridLayoutManager.HORIZONTAL 方向时,4 是行数,表示只有 4 行。
5.2、分割线
没有默认的网格布局分割线,这里我们通过修改 DividerItemDecoration 的源码自定义一个分割线。代码如下:
public class DividerGridItemDecoration extends RecyclerView.ItemDecoration { public static final int HORIZONTAL = LinearLayout.HORIZONTAL; public static final int VERTICAL = LinearLayout.VERTICAL; private static final String TAG = "DividerItem"; private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; private Drawable mDivider; private int mOrientation; private final Rect mBounds = new Rect(); public DividerGridItemDecoration(Context context) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); if (mDivider == null) { Log.w(TAG, "@android:attr/listDivider was not set in the theme used for this " + "DividerItemDecoration. Please set that attribute all call setDrawable()"); } a.recycle(); } public void setDrawable(@NonNull Drawable drawable) { if (drawable == null) { throw new IllegalArgumentException("Drawable cannot be null."); } mDivider = drawable; } @Nullable public Drawable getDrawable() { return mDivider; } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { if (parent.getLayoutManager() == null || mDivider == null) { return; } drawVertical(c, parent); drawHorizontal(c, parent); } private void drawVertical(Canvas canvas, RecyclerView parent) { canvas.save(); final int left; final int right; //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides. if (parent.getClipToPadding()) { left = parent.getPaddingLeft(); right = parent.getWidth() - parent.getPaddingRight(); canvas.clipRect(left, parent.getPaddingTop(), right, parent.getHeight() - parent.getPaddingBottom()); } else { left = 0; right = parent.getWidth(); } final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); parent.getDecoratedBoundsWithMargins(child, mBounds); final int bottom = mBounds.bottom + Math.round(child.getTranslationY()); final int top = bottom - mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(canvas); } canvas.restore(); } private void drawHorizontal(Canvas canvas, RecyclerView parent) { canvas.save(); final int top; final int bottom; //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides. if (parent.getClipToPadding()) { top = parent.getPaddingTop(); bottom = parent.getHeight() - parent.getPaddingBottom(); canvas.clipRect(parent.getPaddingLeft(), top, parent.getWidth() - parent.getPaddingRight(), bottom); } else { top = 0; bottom = parent.getHeight(); } final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds); final int right = mBounds.right + Math.round(child.getTranslationX()); final int left = right - mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(canvas); } canvas.restore(); } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (mDivider == null) { outRect.set(0, 0, 0, 0); return; } if (mOrientation == VERTICAL) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } }
添加分割线
DividerGridItemDecoration gridItemDecoration=new DividerGridItemDecoration(this);
mRecyclerView.addItemDecoration(gridItemDecoration);
运行效果如下
5.3、每个item占用的格数
使用setSpanSizeLookup函数,其中传入一个GridLayoutManager.SpanSizeLookup对象,其内部有一个抽象函数getSpanSize(),你可以设置返回的数值,让当前的item占据几个位置,当然返回的int型数值只能小于等于GridLayoutManager设置span的个数,比如每行item的个数为4个,然后你设置返回5,就会报错。
首先我们不能再以上面的方式添加分割线了,而是通过设置item的样式来设置分割线,为了更加直观添加了一个颜色。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="1dp"
android:color="#000000" />
<solid android:color="@color/colorAccent" />
</shape>
设置每个数据占用的格数。
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (position == 0) {
return 4;
} else if (position == 2) {
return 3;
} else {
return 1;
}
}
});
这里设置第1个数据占用4格,第3个数据占用3格,其余的都只占用一格。效果图如下。
6.1、修改 item 布局
为了实现方便,瀑布流不用分割线,我们定义 item 的分割距离为 2dp,为了更加直观,我们还给 item 添加了一个颜色。
<?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:layout_margin="2dp"
android:background="@color/colorPrimary"
android:orientation="vertical">
<TextView
android:id="@+id/tvItem"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center" />
</LinearLayout>
6.2、每个 item 的高度
通常这个高度是由服务器返回的数据高度来控制的,在这里我们写一个随机高度来控制 item。
mHeights = new ArrayList<>();
for (int i = 0; i < mList.size(); i++) {
mHeights.add((int) (100 + Math.random() * 300));
}
设置 item 的高度
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.itemView.setTag(position);
holder.tv.setText(mList.get(position));
ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();
lp.height = mHeights.get(position);
holder.tv.setLayoutParams(lp);
}
运行效果如下
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。