RecyclerView 分组 和吸顶效果
主要利用ItemDecoration 中的三个方法,不了解的可以参考;
分组
分组效果
思路
- 数据部分可以通过内容或者标志位来区分是不是第一个,例子中通过标志位区分
- ItemDecoration 定义一个接口来实现数据传递
- ItemDecoration 中getItemOffsets方法给山西省 、河南省这部分留出空间
- ItemDecoration 中onDrawOver 方法绘制矩形和文字
其他方式实现参考--RecyclerView 分组实现(一)
实现
Activity中
- initData() 初始化数据,给标志位来区分数据
- 调用SectionItemDecoration中定义的接口实现数据传递
package com.example.tuionf.recyclerviewlearn;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class SectionActivity extends AppCompatActivity {
private RecyclerView sectionRv;
private List mList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_section);
initData();
sectionRv = (RecyclerView) findViewById(R.id.section_rv);
sectionRv.setLayoutManager(new LinearLayoutManager(this));
SectionAdapter sectionAdapter = new SectionAdapter(this,mList);
sectionRv.addItemDecoration(new SectionItemDecoration(this, new SectionItemDecoration.DecorationCallback() {
@Override
public boolean isGroupFirst(int position) {
return mList.get(position).isFirst();
}
@Override
public String getGroupFirstLine(int position) {
return mList.get(position).getTag();
}
}));
sectionRv.setAdapter(sectionAdapter);
}
private void initData() {
for (int i = 0; i < 10; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("山西省");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
for (int i = 0; i < 20; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("辽宁省");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
for (int i = 0; i < 25; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("河南省");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
for (int i = 0; i < 29; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("广东省");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
for (int i = 0; i < 20; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("北京市");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
for (int i = 0; i < 20; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("天津市");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
for (int i = 0; i < 20; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("重庆市");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
for (int i = 0; i < 19; i++) {
SectionBean sectionBean = new SectionBean();
sectionBean.setText("--" + i);
sectionBean.setTag("山东省");
if (i == 0){
sectionBean.setFirst(true);
}else {
sectionBean.setFirst(false);
}
mList.add(sectionBean);
}
}
}
SectionItemDecoration中
- 定义接口
- 实现三个方法
package com.example.tuionf.recyclerviewlearn;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.v7.widget.RecyclerView;
import android.text.TextPaint;
import android.util.Log;
import android.view.View;
/**
* Created by tuion on 2017/9/7.
*/
public class SectionItemDecoration extends RecyclerView.ItemDecoration {
private TextPaint textPaint;
private Paint paint;
private int topGap = 43;
private Paint.FontMetrics fontMetrics;
private DecorationCallback callback;
private static final String TAG = "SectionItemDecoration";
public SectionItemDecoration(Context context,DecorationCallback decorationCallback) {
Resources res = context.getResources();
this.callback = decorationCallback;
paint = new Paint();
paint.setColor(res.getColor(R.color.colorAccent));
textPaint = new TextPaint();
textPaint.setTypeface(Typeface.DEFAULT_BOLD);
textPaint.setAntiAlias(true);
textPaint.setTextSize(80);
textPaint.setColor(Color.BLACK);
textPaint.getFontMetrics(fontMetrics);
textPaint.setTextAlign(Paint.Align.LEFT);
fontMetrics = new Paint.FontMetrics();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
Log.e(TAG, "onDraw: " );
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
Log.e(TAG, "onDrawOver: " );
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
String textLine = "~~~"+callback.getGroupFirstLine(position)+"~~~";
if (position == 0 || callback.isGroupFirst(position)) {
float top = view.getTop() - topGap;
float bottom = view.getTop();
c.drawRect(left, top, right, bottom, paint);//绘制红色矩形
c.drawText(textLine, left, bottom, textPaint);//绘制文本
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int pos = parent.getChildAdapterPosition(view);
Log.e(TAG, "getItemOffsets: ---"+pos );
if (pos == 0 || callback.isGroupFirst(pos)) {//同组的第一个才添加padding
outRect.top = topGap;
} else {
outRect.top = 0;
}
}
public interface DecorationCallback {
boolean isGroupFirst(int position);
String getGroupFirstLine(int position);
}
}
吸顶效果
效果
懒得做GIF了,百度一下吸顶效果应该可以理解
思路
- onDrawOver()方法,可以绘制在内容的上面,覆盖内容—主要就是利用这个特点实现的
实现
- 和上面基本一样,区别就在于 onDrawOver() 方法
//这个可以实现吸顶效果
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
Log.e(TAG, "onDrawOver: " );
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
String preGroupName; //标记上一个item对应的Group
String currentGroupName = null; //当前item对应的Group
for (int i = 0; i < childCount; i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
preGroupName = currentGroupName;
currentGroupName = callback.getGroupFirstLine(position);
if (currentGroupName == null || TextUtils.equals(currentGroupName, preGroupName))
continue;
int viewBottom = view.getBottom();
float top = Math.max(topGap, view.getTop());//top 决定当前顶部第一个悬浮Group的位置
if (position + 1 < childCount) {
//获取下个GroupName
String nextGroupName = callback.getGroupFirstLine(position + 1);
if (!currentGroupName.equals(nextGroupName) && viewBottom < top) {
top = viewBottom;
}
}
//根据top绘制group
c.drawRect(left, top - topGap, right, top, paint);
Paint.FontMetrics fm = textPaint.getFontMetrics();
//文字竖直居中显示
float baseLine = top - (topGap - (fm.bottom - fm.top)) / 2 - fm.bottom;
c.drawText(currentGroupName, left, baseLine, textPaint);
}
}