不断学习,做更好的自己!💪
视频号CSDN简书欢迎打开微信,关注我的视频号:KevinDev点我点我 效果图BaseAdapter.java
/**
* Created on 2021/7/16 14:50
*
* @author Gong Youqiang
*/
@SuppressWarnings("ALL")
public abstract class BaseAdapter extends RecyclerView.Adapter
implements View.OnClickListener,View.OnLongClickListener,IAdapterProxy{
// 数据集合
protected List mDataList;
// 监听器
private AdapterListener adapterListener;
public BaseAdapter() {
this(null);
}
public BaseAdapter(AdapterListener adapterListener) {
this(new ArrayList(),adapterListener);
}
public BaseAdapter(List mDataList, AdapterListener adapterListener) {
this.mDataList = mDataList;
this.adapterListener = adapterListener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 创建ViewHolder
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View root = inflater.inflate(viewType,parent,false);
ViewHolder viewHolder = onCreateViewHolder(root,viewType);
// 基础的操作
root.setTag(R.id.recycler_view,viewHolder);
root.setOnClickListener(this);
root.setOnLongClickListener(this);
doWithRoot(viewHolder,root);
return viewHolder;
}
protected void doWithRoot(ViewHolder viewHolder,View root){
}
/**
* 实际的创建ViewHolder的方法
*/
public abstract ViewHolder onCreateViewHolder(View root, int viewType);
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// 设置不能进行重复绘制
//holder.setIsRecyclable(false);
// TODO 对多数据进行测试,查看哪里出了问题
// 绑定数据
Data data = mDataList.get(position);
holder.bind(data);
}
@Override
public int getItemViewType(int position) {
Data data = mDataList.get(position);
return getItemLayout(data,position);
}
/**
* 得到子布局的ID 适合多种子布局的情况下使用
*/
public abstract int getItemLayout(Data data,int position);
@Override
public int getItemCount() {
return mDataList.size();
}
@Override
public void onClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag(R.id.recycler_view);
if(holder != null){
if(adapterListener == null)
return;
int pos = holder.getAdapterPosition();
adapterListener.onItemClick(holder,mDataList.get(pos));
}
}
@Override
public boolean onLongClick(View v) {
ViewHolder holder = (ViewHolder) v.getTag(R.id.recycler_view);
if(holder != null){
if(adapterListener != null){
int pos = holder.getAdapterPosition();
adapterListener.onItemLongClick(holder,mDataList.get(pos));
return true;
}
}
return false;
}
/**
* 得到数据
*/
public List getItems() {
return mDataList;
}
/**
* 新增一个数据
*/
public void add(Data data){
mDataList.add(data);
notifyItemInserted(mDataList.size() -1 );
}
/**
* 新增所有的数据
*/
public void addAllData(Collection datas){
int start = mDataList.size();
mDataList.addAll(datas);
notifyItemRangeChanged(start,datas.size());
}
/**
* 新增所有的数组数据
*/
public void addAllData(Data... datas){
int start = mDataList.size();
mDataList.addAll(Arrays.asList(datas));
notifyItemRangeChanged(start,datas.length);
}
/**
* 删除所有的数据
*/
public void remove(){
mDataList.clear();
notifyDataSetChanged();
}
/**
* 替换数据
*/
public void replace(Collection datas){
mDataList.clear();
mDataList.addAll(datas);
notifyDataSetChanged();
}
public void setAdapterListener(AdapterListener listener){
this.adapterListener = listener;
}
/*
* 适配器的监听器
*/
public interface AdapterListener{
// 单击的时候
void onItemClick(ViewHolder holder, Data data);
// 长按的时候
void onItemLongClick(ViewHolder holder, Data data);
}
/**
* 自定义的ViewHolder
*/
public static abstract class ViewHolder extends RecyclerView.ViewHolder{
protected Data mData;
public ViewHolder(View itemView) {
super(itemView);
}
public void bind(Data data){
mData = data;
onBind(data);
}
/**
* 实现数据的绑定
*/
protected abstract void onBind(Data data);
}
public abstract static class AdapterListenerImpl implements AdapterListener{
@Override
public void onItemClick(ViewHolder holder,Data data) {
}
@Override
public void onItemLongClick(ViewHolder holder,Data data) {
}
}
}
IAdapterProxy.java
/**
* Created on 2021/7/16 14:52
*
* @author Gong Youqiang
*/
public interface IAdapterProxy{
void addAllData(Collection dataList);
void setAdapterListener(BaseAdapter.AdapterListener listener);
}
2. 数据
ITimeItem.java
/**
* Created on 2021/7/16 14:56
* 时间轴数据需要实现的接口
* @author Gong Youqiang
*/
public interface ITimeItem {
/**
* 构建绘制的标题
* @return 标题
*/
String getTitle();
/**
* 用户绘制原点的颜色
* @return 颜色
*/
int getColor();
/**
* 图片的资源文件
* @return drawable的资源地址
*/
int getResource();
}
3. ItemDecoration
TimeLine.java
/**
* Created on 2021/7/16 14:54
*
* @author Gong Youqiang
*/
public abstract class TimeLine extends RecyclerView.ItemDecoration {
// 标题
public static final int FLAG_TITLE_POS_NONE = 0X0001;
public static final int FLAG_TITLE_TYPE_TOP = 0x0002;
public static final int FLAG_TITLE_TYPE_LEFT = 0x0004;
public static final int FLAG_TITLE_DRAW_BG = 0x0008;
public static final int FLAG_SAME_TITLE_HIDE = 0x0100;
// 时间线
public static final int FLAG_LINE_DIVIDE = 0x0010;
public static final int FLAG_LINE_CONSISTENT = 0x0020;
public static final int FLAG_LINE_BEGIN_TO_END= 0x0040;
// 时间点
public static final int FLAG_DOT_RES = 0x1000;
public static final int FLAG_DOT_DRAW = 0x2000;
protected Context mContext;
protected List timeItems;
// 标题放置的类型
protected int mFlag;
// 上次的标题
// 标题分两种,
// 1. 上方
// 2. 左侧
protected int mTitleColor;
protected int mTopOffset;
protected int mLeftOffset;
protected Paint mTextPaint;
protected int mTitleFontSize;
protected int mBgColor;
protected Paint mBgPaint;
// 线
protected int mLineColor;
protected Paint mLinePaint;
protected int mLineOffset;
protected int mLineWidth;
// 点
protected Paint mDotPaint;
public TimeLine(Config config) {
mContext = config.context;
this.timeItems = config.timeItems;
this.mFlag = config.flag;
// 标题
this.mTitleColor = config.titleColor;
if ((mFlag & FLAG_TITLE_TYPE_TOP) != 0) {
mTopOffset = DisplayUtils.dip2px(config.titleOffset);
} else if ((mFlag & FLAG_TITLE_TYPE_LEFT) != 0) {
mLeftOffset = DisplayUtils.dip2px(config.titleOffset);
}
this.mTitleFontSize = DisplayUtils.sp2px(mContext, config.titleFontSize);
this.mBgColor = config.bgColor;
// 时间线
this.mLineColor = config.lineColor;
this.mLineOffset = DisplayUtils.dip2px(config.lineOffset);
this.mLineWidth = DisplayUtils.dip2px(config.lineWidth);
init();
}
private void init() {
mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mLinePaint.setColor(mLineColor);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mTextPaint.setTextSize(mTitleFontSize);
mTextPaint.setColor(mTitleColor);
mBgPaint = new Paint();
mBgPaint.setColor(mBgColor);
mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
}
/**
* 更新部分数据
*/
public void addItems(List items){
this.timeItems.addAll(items);
}
/**
* 更新全部数据
* @param items 数据
*/
public void replace(List items){
this.timeItems = items;
}
/**
* 清除数据
*/
public void remove(){
this.timeItems.clear();
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
// 兼容4.0硬件加速无效
parent.setLayerType(View.LAYER_TYPE_SOFTWARE,mDotPaint);
int childCount = parent.getChildCount();
if (childCount == 0)
return;
// 绘制处理
// 1. 绘制标题
drawTitle(c, parent);
// 2. 绘制线
drawVerticalLine(c, parent);
// 3. 绘制点
drawPoint(c, parent);
}
/**
* 绘制标题
*/
protected abstract void drawTitle(Canvas canvas, RecyclerView parent);
/**
* 绘制直线
* @param c Canvas
* @param parent RecyclerView
*/
protected abstract void drawVerticalLine(Canvas c, RecyclerView parent);
/**
* 绘制点
* @param c Canvas
* @param parent RecyclerView
*/
protected abstract void drawPoint(Canvas c, RecyclerView parent);
public static class Config {
Context context;
List timeItems = new ArrayList();
int flag = 0;
// 标题
int titleColor = Color.parseColor("#4e5864");
int titleFontSize = 20;
int bgColor;
int titleOffset = 40;
// 线
int lineColor = Color.parseColor("#8d9ca9");
int lineOffset = 30;
int lineWidth = 1;
}
public static class Builder {
private Config mConfig;
public Builder(Context context) {
this(context,new ArrayList());
}
public Builder(Context context,List timeItems) {
this.mConfig = new Config();
this.mConfig.context = context;
this.mConfig.timeItems = timeItems;
}
/**
* 设置标题
*
* @param titleColor 标题文本的颜色
* @param fontSize 标题文本的大小 dp
* @param bgColor 背景颜色
*/
public Builder setTitle(int titleColor, int fontSize, int bgColor) {
this.mConfig.titleColor = titleColor;
this.mConfig.titleFontSize = fontSize;
this.mConfig.bgColor = bgColor;
this.mConfig.flag |= FLAG_TITLE_DRAW_BG;
return this;
}
/**
* 设置标题
*
* @param titleColor 标题文本的颜色
* @param fontSize 标题文本的大小 dp
*/
public Builder setTitle(int titleColor, int fontSize) {
this.mConfig.titleColor = titleColor;
this.mConfig.titleFontSize = fontSize;
return this;
}
/**
* 可以设置Title的位置,比如将标题设置在顶部或者将标题设置左边
*
* @param type 类型 FLAG_TITLE_POS_NONE/FLAG_TITLE_TYPE_TOP/FLAG_TITLE_TYPE_LEFT
* @param titleOffset 偏移量
*/
public Builder setTitleStyle(int type, int titleOffset) {
this.mConfig.flag |= type;
this.mConfig.titleOffset = titleOffset;
return this;
}
/**
* 启动隐藏相同标题
*/
public Builder setSameTitleHide() {
this.mConfig.flag |= FLAG_SAME_TITLE_HIDE;
return this;
}
/**
* @param type type 时间线的类型
* @param lineOffset 时间轴左边偏移的大小,右边也会偏移同样的大小
*/
public Builder setLine(int type, int lineOffset, int lineColor) {
return setLine(type, lineOffset, lineColor,1);
}
/**
* @param type type 时间线的类型
* @param lineOffset 时间轴左边偏移的大小,右边也会偏移同样的大小
*/
public Builder setLine(int type, int lineOffset, int lineColor,int lineWidth) {
this.mConfig.flag |= type;
this.mConfig.lineOffset = lineOffset;
this.mConfig.lineColor = lineColor;
this.mConfig.lineWidth = lineWidth;
return this;
}
/**
* 设置原点
*
* @param type 点的类型
*/
public Builder setDot(int type) {
this.mConfig.flag |= type;
return this;
}
/**
* 构建
*
* @param cls 构建的类
* @return T
*/
public TimeLine build(Class cls) {
TimeLine t = null;
try {
Constructor con = cls.getConstructor(Config.class);
t = con.newInstance(mConfig);
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
return t;
}
}
}
DoubleTimeLineDecoration.java
/**
* Created on 2021/7/19 9:04
*
* @author Gong Youqiang
*/
public abstract class DoubleTimeLineDecoration extends TimeLine {
public static final int LEFT = 0;
public static final int RIGHT = 1;
private int mStartSide;
public DoubleTimeLineDecoration(Config config) {
super(config);
mStartSide = LEFT;
}
/**
* 设置起始边
* @param startSide Left RIGHT
*/
public void setStartSide(int startSide) {
this.mStartSide = startSide;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
// 这里应该不需要偏移了
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
int pos = params.getViewAdapterPosition();
ITimeItem timeItem = timeItems.get(pos);
int side = pos % 2;
if ((mFlag & FLAG_TITLE_TYPE_LEFT) != 0) {
if (side == mStartSide)
outRect.set(0, 0, (mLineOffset+mLineWidth)/2 + mLeftOffset, 0);
else
outRect.set((mLineOffset+mLineWidth)/2 + mLeftOffset, 0, 0, 0);
} else {
if (side == mStartSide)
outRect.set(0, 0, (mLineOffset+mLineWidth)/2, 0);
else
outRect.set((mLineOffset+mLineWidth)/2, 0, 0, 0);
}
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
// 兼容4.0硬件加速无效
parent.setLayerType(View.LAYER_TYPE_SOFTWARE, mDotPaint);
int childCount = parent.getChildCount();
if (childCount == 0)
return;
// 绘制处理
// 1. 绘制标题
drawTitle(c, parent);
// 2. 绘制线
drawVerticalLine(c, parent);
// 3. 绘制点
drawPoint(c, parent);
}
/**
* 绘制标题
*/
@Override
protected void drawTitle(Canvas canvas, RecyclerView parent) {
int childCount = parent.getChildCount();
// 注意:隐藏相同标题对两侧布局不重要
int centerX = parent.getMeasuredWidth() / 2;
for (int i = 0; i = parent.getMeasuredWidth() / 2) {
mLeft = parent.getPaddingLeft();
mTop = child.getTop();
mRight = child.getLeft() - params.leftMargin;
mBottom = child.getBottom();
if ((mFlag & FLAG_TITLE_DRAW_BG) != 0)
canvas.drawRect(mLeft, mTop, mRight, mBottom, mBgPaint);
onDrawTitleItem(canvas, mLeft, mTop, mRight, mBottom, centerX, pos, false);
} else {
mLeft = child.getRight() + params.rightMargin;
mTop = child.getTop();
mRight = parent.getMeasuredWidth() - parent.getPaddingRight();
mBottom = child.getBottom();
if ((mFlag & FLAG_TITLE_DRAW_BG) != 0)
canvas.drawRect(mLeft, mTop, mRight, mBottom, mBgPaint);
onDrawTitleItem(canvas, mLeft, mTop, mRight, mBottom, centerX, pos, true);
}
}
}
}
/**
* 绘制标题
*
* @param left 绘制文本区域范围
* @param top 绘制文本区域范围
* @param right 绘制文本区域范围
* @param bottom 绘制文本区域范围
* @param pos 使用数据的位置
*/
protected abstract void onDrawTitleItem(Canvas canvas, int left, int top, int right, int bottom, int centerX, int pos, boolean isLeft);
@Override
protected void drawVerticalLine(Canvas c, RecyclerView parent) {
int top = parent.getPaddingTop();
final int left = parent.getPaddingLeft();
int bottom;
int childCount = parent.getChildCount();
if ((mFlag & FLAG_LINE_CONSISTENT) != 0) {
View lastChild = parent.getChildAt(childCount - 1);
bottom = lastChild.getBottom();
c.drawLine(parent.getMeasuredWidth() / 2, top, parent.getMeasuredWidth() / 2, bottom, mLinePaint);
} else {
View firstChild = parent.getChildAt(0);
top = (firstChild.getTop() + firstChild.getBottom()) / 2;
View lastChild = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) lastChild.getLayoutParams();
if(params.getViewAdapterPosition() == timeItems.size() - 1) {
bottom = (lastChild.getBottom() + lastChild.getTop()) / 2;
}else {
bottom = lastChild.getBottom();
}
c.drawLine(parent.getMeasuredWidth() / 2, top, parent.getMeasuredWidth() / 2, bottom, mLinePaint);
}
}
@Override
protected void drawPoint(Canvas c, RecyclerView parent) {
int childCount = parent.getChildCount();
for (int i = 0; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?