RecyclerView高级应用——自定义ItemDecoration
来源:互联网 发布:手机版经传软件 编辑:程序博客网 时间:2024/05/16 16:17
RecyclerView的用法这里就不讲了,之前加分割线是直接在Item布局加的,后来想想这种解决办法实在是太low了。对技术有追求的人当然要用更高级的办法。啊哈哈哈~
方法讲解
在此之前一定要先介绍一下方法,这样可以更方便你的理解。
我们需要编写一个类继承RecyclerView.ItemDecoration
并重写三种方法:
getItemOffsets:
这个可以简单的理解成为RecyclerView的每一个Item设置一个偏移量你可一个理解成设置了一个margin。
上图就是通过getItemOffsets方法中的 outRect.set(0, 0, 0, 100);进行设置的。
如果我们要为RecyclerView增加分割线,我们应该大致做一下的准备:
1.得到系统默认的listDivider属性,并通过它取得对应的Drawable对象。
2.测量Drawable对象的宽高。
3.根据情况判断是需要水平分割线还是垂直分割线
a.水平分割线: outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());我们应该底部预留分割线的高度。b.垂直分割线: outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);我们应该右侧预留分割线的宽度。
大家可以看到了,右边空出来些东西,是不是很不美观,那当然就需要往上面画一些东西喽。我们就需要用onDraw()这个方法。
onDraw:
这个方法就是重点了,方法的参数里面有一个Canvas c的对象,了解自定义View的人都应该觉得这个方法很相似我们可以在这上面画文字、bitmap、圆等等等等。
onDrawOver:
这个方法是相对与整个视图的,不受Item的限制,比如我们可以在视图的顶部加一个悬浮的层等等。
这三个方法简单的讲到这里,下面通过实践去更深刻的理解。
代码:
class MyItemDecoration extends RecyclerView.ItemDecoration { private final Drawable mLine; private final int orientation; public MyItemDecoration(Context context, int orientation) { this.orientation = orientation; int[] attrs = new int[]{android.R.attr.listDivider}; TypedArray a = context.obtainStyledAttributes(attrs); mLine = a.getDrawable(0); a.recycle(); } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); if (orientation == RecyclerView.HORIZONTAL) { drawVertical(c, parent, state); } else if (orientation == RecyclerView.VERTICAL) { drawHorizontal(c, parent, state); } } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (orientation == RecyclerView.HORIZONTAL) { //画垂直线 outRect.set(0, 0, mLine.getIntrinsicWidth(), 0); } else if (orientation == RecyclerView.VERTICAL) { //画水平线 outRect.set(0, 0, 0, mLine.getIntrinsicHeight()); } } /** * 画垂直分割线 */ private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state) { int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt(i); int left = child.getRight(); int top = child.getTop(); int right = left + mLine.getIntrinsicWidth(); int bottom = child.getBottom(); mLine.setBounds(left, top, right, bottom); mLine.draw(c); } } /** * 画水平分割线 */ private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerView.State state) { int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt(i); int left = child.getLeft(); int top = child.getBottom(); int right = child.getRight(); int bottom = top + mLine.getIntrinsicHeight(); mLine.setBounds(left, top, right, bottom); mLine.draw(c); } } }
我们还可以重新定义一下系统默认分割线的颜色及宽度
style
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="android:listDivider">@drawable/customizelistdivider </item> </style>
customizelistdivider.xml
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <gradient android:endColor="#ff0000ff" android:startColor="#ffff0000" android:type="linear" /> <size android:height="4dp" android:width="4dp"/></shape>
一条华丽丽丽丽的分割线就出来了
有了上述知识的铺垫,我们就可以画出更多好玩的东西了
例如:
简单说一下思路:
思路一
这回我们是在顶部进行预留的区域进行填写字母,但是我们发现不是每一个都预留了区域,只有当前拼音的第一个预留了区域。
这时我们应该进行判断:
a.如果当前的itemPosition为0时,我们需要预留。
b.如果第二个itemPosition所代表的首字母与第一个不同时,我们需要预留。
c.其他情况为0就可以了
@Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { super.getItemOffsets(outRect, itemPosition, parent); int Offsets = 0; String letter = PinyinUtils.getPinyin(mData.get(itemPosition)).charAt(0) + ""; if (itemPosition == 0) { Offsets = dip2px(40); } else { String preLetter = PinyinUtils.getPinyin(mData.get(itemPosition - 1)).charAt(0) + ""; if (!letter.equalsIgnoreCase(preLetter)) { Offsets = dip2px(40); } } outRect.set(0, Offsets, 0, 0); }
思路二
到这一步就是画文字了,我们主要找好每一个Item所对应的高就可以了,至于left,就直接为0就可以了。
注意注意:我们现在所求的上下左右的区间,不是Item的区间,而是我们要画字母的矩形区间
int left = 0; //我们要对多出来的地方减掉 int top = child.getTop() - dip2px(40); int right = child.getRight(); //这时候注意不应该减去dip2px(40),而是要减去Item的高 int bottom = child.getBottom() - child.getMeasuredHeight();
代码:
MyDecoration
public class MyDecoration extends RecyclerView.ItemDecoration { Context mContext; List<User> sortList; Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); public MyDecoration(Context context, List<User> data) { mContext = context; sortList = data; paint.setTextSize(sp2px(16)); paint.setColor(Color.RED); } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); drawLetterToItemLeft(c, parent); } private void drawLetterToItemLeft(Canvas c, RecyclerView parent) { RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { int position = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition() + i; View child = parent.getChildAt(i); int left = 0; int top = child.getTop() - dip2px(40); int right = child.getRight(); int bottom = child.getBottom() - child.getMeasuredHeight(); Rect targetRect = new Rect(left, top, right, bottom); paint.setColor(Color.RED); Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2; //当前名字拼音的第一个字母 String letter = sortList.get(position).getFirstLetter(); if (position == 0) { paint.setColor(Color.parseColor("#eaeaea")); c.drawRect(targetRect, paint); drawLetter(letter, 0, baseline, c, parent); } else { String preLetter = sortList.get(position - 1).getFirstLetter(); if (!letter.equalsIgnoreCase(preLetter)) { paint.setColor(Color.parseColor("#eaeaea")); c.drawRect(targetRect, paint); drawLetter(letter, 0, baseline, c, parent); } } } } private void drawLetter(String letter, float width, float height, Canvas c, RecyclerView parent) { paint.setColor(Color.RED); c.drawText(letter, 0, height, paint); } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { super.getItemOffsets(outRect, itemPosition, parent); int Offsets = 0; String letter = sortList.get(itemPosition).getFirstLetter(); if (itemPosition == 0) { Offsets = dip2px(40); } else { String preLetter = sortList.get(itemPosition - 1).getFirstLetter(); if (!letter.equalsIgnoreCase(preLetter)) { Offsets = dip2px(40); } } outRect.set(0, Offsets, 0, 0); } private int dip2px(int dip) { float density = mContext.getResources().getDisplayMetrics().density; int px = (int) (dip * density + 0.5f); return px; } public int sp2px(int sp) { return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, mContext.getResources().getDisplayMetrics()) + 0.5f); } }
User(此类来源于网络)
public class User implements Comparable<User> { private String name; // 姓名 private String pinyin; // 姓名对应的拼音 private String firstLetter; // 拼音的首字母 public User() { } public User(String name) { this.name = name; pinyin = Cn2Spell.getPinYin(name); // 根据姓名获取拼音 firstLetter = pinyin.substring(0, 1).toUpperCase(); // 获取拼音首字母并转成大写 if (!firstLetter.matches("[A-Z]")) { // 如果不在A-Z中则默认为“#” firstLetter = "#"; } } public String getName() { return name; } public String getPinyin() { return pinyin; } public String getFirstLetter() { return firstLetter; } @Override public int compareTo(User another) { if (firstLetter.equals("#") && !another.getFirstLetter().equals("#")) { return 1; } else if (!firstLetter.equals("#") && another.getFirstLetter().equals("#")){ return -1; } else { return pinyin.compareToIgnoreCase(another.getPinyin()); } }}
Cn2Spell(此类来源于网络)
/** * 汉字转换位汉语拼音,英文字符不变 */public class Cn2Spell { public static StringBuffer sb = new StringBuffer(); /** * 获取汉字字符串的首字母,英文字符不变 * 例如:阿飞→af */ public static String getPinYinHeadChar(String chines) { sb.setLength(0); char[] chars = chines.toCharArray(); HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); for (int i = 0; i < chars.length; i++) { if (chars[i] > 128) { try { sb.append(PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat)[0].charAt(0)); } catch (Exception e) { e.printStackTrace(); } } else { sb.append(chars[i]); } } return sb.toString(); } /** * 获取汉字字符串的第一个字母 */ public static String getPinYinFirstLetter(String str) { sb.setLength(0); char c = str.charAt(0); String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c); if (pinyinArray != null) { sb.append(pinyinArray[0].charAt(0)); } else { sb.append(c); } return sb.toString(); } /** * 获取汉字字符串的汉语拼音,英文字符不变 */ public static String getPinYin(String chines) { sb.setLength(0); char[] nameChar = chines.toCharArray(); HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat(); defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE); defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE); for (int i = 0; i < nameChar.length; i++) { if (nameChar[i] > 128) { try { sb.append(PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0]); } catch (Exception e) { e.printStackTrace(); } } else { sb.append(nameChar[i]); } } return sb.toString(); }}
由于我们用到了排序还需要引入一个jar包
pinyin4j-2.5.0.jar
公众号:
QQ群:
365473065
- RecyclerView高级应用——自定义ItemDecoration
- RecyclerView——ItemDecoration笔记
- 自定义 RecyclerView.ItemDecoration
- recyclerView-自定义itemDecoration详解
- RecyclerView自定义ItemDecoration
- Android——RecyclerView入门学习之ItemDecoration
- RecyclerView.ItemDecoration
- 小甜点,RecyclerView 之 ItemDecoration 讲解及高级特性实践
- 小甜点,RecyclerView 之 ItemDecoration 讲解及高级特性实践
- RecyclerView之ItemDecoration讲解及高级特性实践
- 使用ItemDecoration自定义RecyclerView的分割线实现头布局
- Android 自定义RecyclerView.ItemDecoration(GridLayoutManager布局下)
- Android之RecyclerView——用ItemDecoration装饰你的Item
- RecyclerView.ItemDecoration 使用总结
- RecyclerView之ItemDecoration详解
- RecyclerView.ItemDecoration(笔记)
- RecyclerView中itemDecoration
- RecyclerView之ItemDecoration详解
- Eclipse设置条件断点
- 实现页面三秒跳转
- 购物车 自定义加减器
- ansible Introduction To Ad-Hoc Commands:
- Arcgis---从数据库中获取数据绘制道路
- RecyclerView高级应用——自定义ItemDecoration
- 通过super调用父类属性和方法
- 第八周(1)项目5---计数的模式匹配
- MyBatis中 javaType及 jdbcType对照关系表
- Oracle的exp增量备份说明(不实用)
- 二级列表购物车的实现逻辑——wyh
- ifly error code 讯飞离线识别错误码
- Cosbench测试s3 ceph对象存储
- JQ中trigger()方法