高级UI-RecyclerView间隔线添加
上文讲到了RecyclerView的简单使用,知道RecycleView是怎么使用的了,那么这一节将基于上一届的内容继续改进,在ListView中很轻松就能实现的间隔线,在RecycleView中也需要自己去实现,那么这一篇文章就来实现间隔线的添加,当然也包括边框线
添加说明
间隔线添加在线性布局中,边框线添加在网格布局中
在RecycleView中,存在抽象类ItemDecoration,我们需要实现这个类,然后就可以愉快的画线了
实现这个类,需要完成两个方法,一个是onDraw(),用于回调的绘制方法,一个是getItemOffsets(),用于得到Item的偏移量
实现间隔线
由于线性布局涉及到水平和竖直,所以这里也要做出相应的判断
public class MyDividerItemDecoration extends RecyclerView.ItemDecoration {
private int orientation = LinearLayoutManager.VERTICAL;
private Drawable divider;
private final int[] attrs = new int[]{android.R.attr.listDivider};
public MyDividerItemDecoration(Context context, int orientation) {
TypedArray typedArray = context.obtainStyledAttributes(attrs);
divider = typedArray.getDrawable(0);
typedArray.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != LinearLayoutManager.VERTICAL
&& orientation != LinearLayoutManager.HORIZONTAL) {
throw new IllegalArgumentException("unsupport type");
}
this.orientation = orientation;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (orientation == LinearLayoutManager.VERTICAL) {
outRect.set(0, 0, 0, divider.getIntrinsicHeight());
} else {
outRect.set(0, 0, divider.getIntrinsicWidth(), 0);
}
}
//RecyclerView回调绘制方法
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (orientation == LinearLayoutManager.VERTICAL) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
super.onDraw(c, parent, state);
}
private void drawHorizontal(Canvas c, RecyclerView parent) {
int top = parent.getPaddingTop();
int bottom = parent.getHeight() - parent.getPaddingBottom();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
int right = left + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
private void drawVertical(Canvas c, RecyclerView parent) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
int bottom = top + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
}
在线性布局中调用
public class LineActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private MyRecyclerViewAdapter adapter;
private List<String> list;
private MyDividerItemDecoration decor;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_line);
recyclerView = (RecyclerView) findViewById(R.id.line_recyclerview);
list = DataUtils.initData(100);
adapter = new MyRecyclerViewAdapter(list);
//设置点击监听
adapter.setOnItemClickListener(new MyRecyclerViewAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(LineActivity.this, "点击 item " + position, Toast.LENGTH_SHORT).show();
}
});
//设置样式,默认垂直
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//水平布局
//recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));
//绘制间隔线
if(decor != null){
recyclerView.removeItemDecoration(decor);
}
decor = new MyDividerItemDecoration(this,LinearLayoutManager.VERTICAL);
recyclerView.addItemDecoration(decor);
recyclerView.setAdapter(adapter);
}
}
实现效果如下图

实现边框线
实现边框线和实现间隔线的思路一致,间隔线是绘制一侧,而边框线是绘制两侧,这是为了防止线条重合,造成整体不美观
首先依旧是要实现ItemDecoration
public class AroundItemDividerDecoration extends RecyclerView.ItemDecoration {
private Drawable divider;
private final int[] attrs = new int[]{android.R.attr.listDivider};
public AroundItemDividerDecoration(Context context) {
divider = context.getResources().getDrawable(R.drawable.item_divider);
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
int right = divider.getIntrinsicWidth();
int bottom = divider.getIntrinsicHeight();
if (isLastColum(itemPosition, parent)) {
right = 0;
}
if (isLastRow(itemPosition, parent)) {
bottom = 0;
}
outRect.set(0, 0, right, bottom);
}
private boolean isLastRow(int itemPosition, RecyclerView parent) {
int spanCount = getSpanCount(parent);
if (spanCount == -1) {
return false;
}
int childCount = parent.getAdapter().getItemCount();
int lastRowCount = childCount % spanCount;
if (lastRowCount == 0 || lastRowCount < spanCount) {
return true;
}
return false;
}
private boolean isLastColum(int itemPosition, RecyclerView parent) {
int spanCount = getSpanCount(parent);
if (spanCount == -1) {
return false;
}
if ((itemPosition + 1) % spanCount == 0) {
return true;
}
return false;
}
private int getSpanCount(RecyclerView parent) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager grid = (GridLayoutManager) parent.getLayoutManager();
int spanCount = grid.getSpanCount();
return spanCount;
}
return -1;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
drawVertical(c, parent);
drawHorizontal(c, parent);
}
private void drawHorizontal(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getLeft() - params.leftMargin;
int right = child.getRight() + params.rightMargin;
int top = child.getBottom() + params.bottomMargin;
int bottom = top + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
private void drawVertical(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int left = child.getRight() + params.rightMargin;
int right = left + divider.getIntrinsicWidth();
int top = child.getTop() - params.topMargin;
int bottom = child.getBottom() + params.bottomMargin;
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
}
这里使用的是一个自定义的分割线
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="2dp"
android:height="2dp" />
<solid android:color="#00ff00" />
</shape>
最后在网格布局中调用
public class GridActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private MyRecyclerViewAdapter adapter;
private List<String> list;
private AroundItemDividerDecoration decor;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid);
recyclerView = (RecyclerView) findViewById(R.id.grid_recyclerview);
list = DataUtils.initData(100);
adapter = new MyRecyclerViewAdapter(list);
//设置样式
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
recyclerView.setAdapter(adapter);
if(decor != null){
recyclerView.removeItemDecoration(decor);
}
decor = new AroundItemDividerDecoration(this);
recyclerView.addItemDecoration(decor);
}
}
实现效果如下图所示

补充:添加Item
要添加Item,只要知道位置便可,在RecycleView中,数据刷新的方式更加高效,添加了很多局部刷新的方法
在适配器中添加如下方法,便可实现数据添加,删除类似
public void addData(int postion) {
list.add(postion, "addItem" + postion);
notifyItemInserted(postion);
}
然后在activity中调用,为了使画面不那么突兀,添加动画效果
public class LineActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private MyRecyclerViewAdapter adapter;
private List<String> list;
private MyDividerItemDecoration decor;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_line);
recyclerView = (RecyclerView) findViewById(R.id.line_recyclerview);
list = DataUtils.initData(100);
adapter = new MyRecyclerViewAdapter(list);
//设置点击监听
adapter.setOnItemClickListener(new MyRecyclerViewAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(LineActivity.this, "点击 item " + position, Toast.LENGTH_SHORT).show();
}
});
//设置样式,默认垂直
recyclerView.setLayoutManager(new LinearLayoutManager(this));
//水平布局
//recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true));
//设置Item动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
//绘制间隔线
if(decor != null){
recyclerView.removeItemDecoration(decor);
}
decor = new MyDividerItemDecoration(this,LinearLayoutManager.VERTICAL);
adapter.notifyDataSetChanged();
recyclerView.addItemDecoration(decor);
recyclerView.setAdapter(adapter);
}
public void addItem(View view) {
adapter.addData(2);
}
}
实现效果如下

源代码:链接:https://pan.baidu.com/s/13wDP14_cTlrul-YJHgavgg 密码:7vr0
高级UI-RecyclerView间隔线添加的更多相关文章
- Android 高级UI设计笔记20:RecyclerView 的详解之RecyclerView添加Item点击事件
1. 引言: RecyclerView侧重的是布局的灵活性,虽说可以替代ListView但是连基本的点击事件都没有,这篇文章就来详细讲解如何为RecyclerView的item添加点击事件,顺便复习一 ...
- Android 高级UI设计笔记07:RecyclerView 的详解
1. 使用RecyclerView 在 Android 应用程序中列表是一个非常重要的控件,适用场合非常多,如新闻列表.应用列表.消息列表等等,但是从Android 一出生到现在并没有非常 ...
- C#使用 DirectX SDK 9做视频播放器 并在视频画线添加文字 VMR9
视频图像处理系列 索引 VS2013下测试通过. 在百度中搜索关键字“DirectX SDk”,或者进入微软官网https://www.microsoft.com/en-us/download/det ...
- firefox 扩展开发笔记(三):高级ui交互编程
firefox 扩展开发笔记(三):高级ui交互编程 前言 前两篇链接 1:firefox 扩展开发笔记(一):jpm 使用实践以及调试 2:firefox 扩展开发笔记(二):进阶开发之移动设备模拟 ...
- 安卓高级3 RecyclerView 和cardView使用案例
cardView: 添加依赖:在Studio搜索cardview即可 在V7包中 或者直接在gradle中添加 compile 'com.android.support:cardview-v7:24. ...
- RecyclerView.ItemDecoration 间隔线
内容已更新到:https://www.cnblogs.com/baiqiantao/p/19762fb101659e8f4c1cea53e7acb446.html 目录一个通用分割线ItemDecor ...
- Android 高级编程 RecyclerView 控件的使用
RecyclerView 是Android 新添加的一个用来取代ListView的控件,它的灵活性与可替代性比listview更好. 看一下继承关系: ava.lang.Object ↳ and ...
- iOS开发——高级UI&带你玩转UITableView
带你玩装UITableView 在实际iOS开发中UITableView是使用最多,也是最重要的一个控件,如果你不会用它,那别说什么大神了,菜鸟都不如. 其实关于UItableView事非常简单的,实 ...
- 高级UI晋升之View渲染机制(二)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 优化性能一般从渲染,运算与内存,电量三个方面进行,今天开始说聊一聊Android ...
随机推荐
- firewall 相关命令
1.firewalld的基本使用 启动: systemctl start firewalld 查看状态: systemctl status firewalld 停止: systemctl disabl ...
- QT项目之创建.pri文件
做大项目的时候,有很多.h和.cpp文件,会很繁琐.就需要.pri文件夹,将大项目分解成一个个的子项目,方便理清思绪和后期维护. 废话不多说,直接上过程! 第一步:新建一个项目.如图,选择choose ...
- Python多线程笔记(二)
Lock对象 原语锁(互斥锁)是一个同步原语,状态是"已锁定"或者"未锁定"之一.两个方法acquire()和release()用于修改锁的状态.如果状态为已锁 ...
- Unity与Android之间的交互之AndroidManifest
https://blog.csdn.net/qq_15003505/article/details/70231975 AndroidManifest,中文名一般称之为清单文件.它描述了应用程序的组件的 ...
- Vue进阶(Bus/作用域slot/动态组件)
一.Vue非父子组件传值(Bus/总线/发布订阅模式/观察者模式) 我们在之前已经知道了父子传值.父组件传递过来了的值,在子组件通过props接受,然后就可以使用了. 也学过了隔代传值,均是通过pro ...
- Arts打卡第5周
Algorithm.主要是为了编程训练和学习. 每周至少做一个 leetcode 的算法题(先从Easy开始,然后再Medium,最后才Hard). 进行编程训练,如果不训练你看再多的算法书,你依然不 ...
- js中的一些隐式转换和总结
js中的不同的数据类型之间的比较转换规则如下: 1. 对象和布尔值比较 对象和布尔值进行比较时,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字 [] == true; //false [] ...
- html 与 xml 的区别与联系
[引言] 前一阵子刚刚学习了html(HyperText Markup Language),最近又接触了xml(Extensible Markup Language),它们之间有什么联系和区别呢?现在 ...
- 组合数学---P1358 扑克牌
P1358 扑克牌 题解 组合数学 Π c[剩余未选牌数][ai] ( i = 1,2,...,m ) 注意 组合数也要取模,不然数字太大会炸 组合数的具体实现就是Dp啊 代码 #include< ...
- redis json 降低性能 使用 hash
使用hashtable和hash-max-zipmap-entries内存优化和效率http://www.flyfifi.cn/blog/detail/71/