您当前的位置:首页 > 电脑百科 > 程序开发 > 移动端 > Android

Android 自定义 View 实现横行时间轴

时间:2019-12-09 15:56:08  来源:  作者:

Android 自定义 View 实现横行时间轴

本篇文章会说下如何使用并且要用麻烦的自定义 view 去实现时间轴效果,以及如何分析、实现自定义 view。 需要具备的知识:Paint、Canvas、自定义 view 的绘制流程。

欢迎留言交流。

一、已经有很多 RecycleView 实现时间轴的例子,为何还要费劲的使用自定义 view 去实现时间轴?

首先看下最终想要的效果:

Android 自定义 View 实现横行时间轴

 

根据上图可以总结出以下几点:

  1. 每个阶段要显示时间、阶段名、状态图标、中间有虚线;
  2. 文字上下交错显示;
  3. 相邻阶段的文字在垂直方向上是可以相交的;
  4. 时间轴的个数不确定,但是要铺满屏幕并且不可滑动; 如果只实现上两点的效果,使用 RecycleView 无疑是最好的选择,但是要同时实现以上整个效果目前想到的最好的办法就是使用自定义 view。

二、如何开始?

相信也有人跟我一样,对自定义的绘制过程 view、canvas、path、paint 的使用有了解,但是真的要去写自定义 view 确不知道从何开始,不知道第一步如何下手。我个人的总结就是:想要的太多,迟迟不动手,所以有想法一定要去动手试验! 不要想着写完第一次运行就是最终想展示的完美效果,而是要抱着整体拆分成不重复的小块,然后去绘制重复块,然后去一点点实现一步步完美的心态才能做出来。

所以首先要把想实现的 view 拆分成一个个小的可绘制的并且没有重复的块,以目前想实现的时间轴效果来说,最小可绘制无重复块也就是只包括一个时间结点的块如图:

Android 自定义 View 实现横行时间轴

 

它包括:

  • 垂直居中的一条虚线;
  • 一个表示状态的图标;
  • 一个显示时间的文本块;
  • 一个显示阶段名的文本块;

三、开始画

有了上面的分析,接下来就要开始画了。

1. 画中间的线

首先画虚线,如果虚线不知道怎么画,可以先画一条实线,然后再去找画虚线的方法。

使用 canvas 中画线的方法 drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint),根据参数得知需知道线的起点与终点坐标以及一个 paint 对象,因为是垂直居中且横穿整个控件的直线所以可以确定两个点的 y 坐标是一样的,也就是控件高的一半,起点的 x 坐标为0,终点的 x 坐标为控件的宽。也就是知道控件的宽和高之后就可以绘制出这条线。获取控件的宽高,可以在 onMeasure 方法中获取:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 mViewWidth = MeasureSpec.getSize(widthMeasureSpec) - dip2px(mContext, mSafeDistance * 2);
 mViewHeight = MeasureSpec.getSize(heightMeasureSpec);
}

画线的代码(在 onDraw 方法中添加,下面其它的绘制方法同样是在 onDraw 方法中添加):

// 定义画笔,并设置相关属性
Paint mLinePaint = new Paint();
mLinePaint.setColor(Color.parseColor("#999999"));
mLinePaint.setStrokeWidth(1);
mLinePaint.setStyle(Paint.Style.STROKE);
// 画虚线
canvas.drawLine(0, mViewHeight / 2, mViewWidth, mViewHeight / 2, mLinePaint);
Android 自定义 View 实现横行时间轴

 

2. 画图标

canvas 画图标的方法:drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint),根据方法的参数去分析如何准备值,这里需要一个 bitmap 对象,起点坐标以及 paint。bitmap 对象可以将资源文件 drawable 转为 bitmap 格式;坐标就是控件的中心点。画图标的代码:

// 图标 x,y 坐标
Bitmap statusBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_no_pass);
float bX = mViewWidth / 2;
// 垂直的中心点在图标的顶部,所以要减去 bitmap 高的一半
float bY = mViewHeight / 2 - statusBitmap.getHeight() / 2f;
Paint mBitmAppaint = new Paint();
mBitmapPaint.setFilterBitmap(true);
canvas.drawBitmap(statusBitmap, bX, bY, mBitmapPaint);

3. 画文本

canvas 画文本的方法:drawText(@NonNull String text, float x, float y, @NonNull Paint paint),依然是根据方法得知需要知道绘制的内容,开始的坐标点以及 paint。当文本在图标上方时,文本的 y 坐标需要使用图标的 y 坐标减去文本到图标的距离,x 坐标同图片的 x 坐标一样;当文本在图标下方时,文本的 y 坐标需要使用图标的 y 坐标加上文本到图标的距离。画文本的代码:

// 定义画笔
Paint mDatePaint = new Paint();
mDatePaint.setColor(Color.parseColor("#666666"));
mDatePaint.setTextSize(dip2px(mContext, 12));
mDatePaint.setStyle(Paint.Style.FILL);
mDatePaint.setTextAlign(Paint.Align.CENTER);
mDatePaint.setAntiAlias(true);

Paint mNamePain = new Paint();
mNamePain.setColor(Color.parseColor("#666666"));
mNamePain.setTextSize(dip2px(mContext, 13));
mNamePain.setStyle(Paint.Style.FILL);
mNamePain.setTextAlign(Paint.Align.CENTER);
mNamePain.setAntiAlias(true);

// 定义坐标变量
float dateX = bX + statusBitmap.getWidth() / 2f;
float dateY;
dateY = mViewHeight / 2 - dip2px(mContext, 19);

// 画文字,在图标上
canvas.drawText("有效时间", dateX, dateY, mNamePain);
canvas.drawText("09.27-09.29", dateX, dateY - dateTextHeight mDatePaint);

// 画文字,在图标下
dateY = mViewHeight / 2 + dip2px(mContext, 19);
canvas.drawText("09.27-09.29", dateX, dateY, mDatePaint);
canvas.drawText("有效时间", dateX, dateY + dateTextHeigh, mNamePain);

4. 由局部到整体

上面已经完成了只有一个时间点的绘制,接下来思考如果有多个时间点时如何绘制。只有一个时间点时计算坐标是以控件的宽高进行计算,那么当有两个时间点的时候需要首先把控件均分成两部分,然后在均分的部分中计算对应的坐标,完成绘制。当有三个时间点的时候需要均分为三部分,然后在各自的部分计算对应的坐标,完成绘制。所以得到不论时间点的个数有多少绘制的方法不会改变,需要改变的是绘制时候用到的点的坐标。其实已经可以看出,当多个点的时候需要循环一下,代码如下:

// 得到多个点时,其中每个部分的宽,itevW 也就等同与上面只有一个时间点时控件的宽
float itemW = mViewWidth / mDataList.size();
for (int i = 0; i < mDataList.size(); i++) {
 // 完成相关计算、绘制
}
Android 自定义 View 实现横行时间轴

 

5. 完善

到这里,整个分析及绘制就差不多要结束了。

绘制虚线的方法:mLinePaint.setPathEffect(new DashPathEffect(new float[]{10, 10}, 0));

绘制虚线时遇到一个问题,在手机上不显示虚线效果,后来查到需要关闭 view 层的硬件加速:setLayerType(View.LAYER_TYPE_SOFTWARE, null);

绘制文本时的中心点计算需要注意下,可以 参考

paint、bitmap 等变量的初始化建议放到初始化方法中去做,不建议在 onDraw 方法中做。

四、总结

关于自定义 view 一定要多看,多尝试。

 


 


Tags:Android   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
今天面试遇到同学说做过内存优化,于是我一般都会问那 Bitmap 的像素内存存在哪?大多数同学都回答在 java heap 里面,就比较尴尬,理论上你做内存优化,如果连图片这个内存大户内存...【详细内容】
2021-12-23  Tags: Android  点击:(8)  评论:(0)  加入收藏
Android logcat日志封装logcat痛点在Android开发中使用logcat非常频繁,logcat能帮我们定位问题,但是在日常使用中发现每次使用都需要传递tag,并且会遇到输出频率很高的log,在多...【详细内容】
2021-12-22  Tags: Android  点击:(8)  评论:(0)  加入收藏
对项目的基本介绍 1.整个框架主要是给MVVM框架使用的,自己写完interface接口后,通过自定义的注解就能自动生成接口方法 2.用Kotlin的Flow去代替Rxjava,因为我发现RxJava功能很...【详细内容】
2021-12-08  Tags: Android  点击:(17)  评论:(0)  加入收藏
前言在Android开发过程中,有些时候会根据需要引用别的项目到当前项目里面,而且以Module形式引用。所以本篇博文就来分享一下怎么以Module形式引用别的项目到当前项目中,方便开...【详细内容】
2021-12-07  Tags: Android  点击:(22)  评论:(0)  加入收藏
新型Android恶意木马程序伪装成数十款街机、射击和策略游戏,通过华为应用市场AppGallery进行分发,从而窃取设备信息和用户的手机号码,全球目前至少有930万台Android设备被该恶...【详细内容】
2021-12-01  Tags: Android  点击:(24)  评论:(0)  加入收藏
作者:fundroid这篇文章偏阅读一些,大家可以了解下 Android 的一些最新动向。每年9/10月份 Google 都会举行约为期2天的 Android Dev Summit,在活动上 Google 的技术专家们会分...【详细内容】
2021-11-30  Tags: Android  点击:(15)  评论:(0)  加入收藏
一、 准备工作1、安装JDK,下载地址(可能需要一个oracle账号,大家百度一下或者自行注册一个就行。尽可能选择8或者11,这两个是长期版本)Java SE | Oracle Technology Network | Or...【详细内容】
2021-11-23  Tags: Android  点击:(28)  评论:(0)  加入收藏
如果你是一名忠实的Android玩家,那么可能会知道,今年的Android 12系统在版本规划上与“往届”相比可以说是很有些特殊。具体来说,除了前段时间刚刚推出正式版的Android 12外,谷...【详细内容】
2021-11-10  Tags: Android  点击:(24)  评论:(0)  加入收藏
使用Maven Publish Plugin插件。(官方支持)一、在Library的build.gradle中配置plugins { id &#39;com.android.library&#39; id &#39;kotlin-android&#39; id &#39;k...【详细内容】
2021-11-05  Tags: Android  点击:(37)  评论:(0)  加入收藏
今年5月,谷歌推出了Android 12,这是原生安卓系统史上最大的设计变化,10月4日,谷歌推出全新的Android12正式版本,并且宣布会在今年晚些时候应用于安卓设备,对比Android11的挤牙膏式...【详细内容】
2021-10-29  Tags: Android  点击:(125)  评论:(0)  加入收藏
▌简易百科推荐
今天面试遇到同学说做过内存优化,于是我一般都会问那 Bitmap 的像素内存存在哪?大多数同学都回答在 java heap 里面,就比较尴尬,理论上你做内存优化,如果连图片这个内存大户内存...【详细内容】
2021-12-23  像程序那样思考    Tags:Android开发   点击:(8)  评论:(0)  加入收藏
Android logcat日志封装logcat痛点在Android开发中使用logcat非常频繁,logcat能帮我们定位问题,但是在日常使用中发现每次使用都需要传递tag,并且会遇到输出频率很高的log,在多...【详细内容】
2021-12-22  YuCoding    Tags:Android   点击:(8)  评论:(0)  加入收藏
对项目的基本介绍 1.整个框架主要是给MVVM框架使用的,自己写完interface接口后,通过自定义的注解就能自动生成接口方法 2.用Kotlin的Flow去代替Rxjava,因为我发现RxJava功能很...【详细内容】
2021-12-08  网易Leo    Tags:Android开发   点击:(17)  评论:(0)  加入收藏
前言在Android开发过程中,有些时候会根据需要引用别的项目到当前项目里面,而且以Module形式引用。所以本篇博文就来分享一下怎么以Module形式引用别的项目到当前项目中,方便开...【详细内容】
2021-12-07  网易Leo    Tags:Android开发   点击:(22)  评论:(0)  加入收藏
作者:fundroid这篇文章偏阅读一些,大家可以了解下 Android 的一些最新动向。每年9/10月份 Google 都会举行约为期2天的 Android Dev Summit,在活动上 Google 的技术专家们会分...【详细内容】
2021-11-30  像程序那样思考    Tags:Android开发   点击:(15)  评论:(0)  加入收藏
一、 准备工作1、安装JDK,下载地址(可能需要一个oracle账号,大家百度一下或者自行注册一个就行。尽可能选择8或者11,这两个是长期版本)Java SE | Oracle Technology Network | Or...【详细内容】
2021-11-23  永沧    Tags:Android   点击:(28)  评论:(0)  加入收藏
使用Maven Publish Plugin插件。(官方支持)一、在Library的build.gradle中配置plugins { id &#39;com.android.library&#39; id &#39;kotlin-android&#39; id &#39;k...【详细内容】
2021-11-05  羊城小阳    Tags:Android   点击:(37)  评论:(0)  加入收藏
谷歌离推出Play Store应用程序的新数据隐私部分又近了一步。应用程序开发人员现在可以通过谷歌在Play控制台的新 "数据安全表 "填写相关细节。该公司表示,所需信息将从2022年...【详细内容】
2021-10-20    中关村在线  Tags:安卓   点击:(58)  评论:(0)  加入收藏
架构究竟是什么?如何更好的理解架构?我们知道一个APP通常是由class组成,而这些class之间如何组合,相互之间又如何产生作用,就是影响这个APP的关键点。细分的话我们可以将其分为类...【详细内容】
2021-09-17  像程序那样思考    Tags:Android架构   点击:(52)  评论:(0)  加入收藏
概述当Android应用程序需要访问设备上的敏感资源时,应用程序开发人员会使用权限模型。虽然该模型使用起来非常简单,但开发人员在使用权限时容易出错,从而导致安全漏洞。本文中,...【详细内容】
2021-09-07  SecTr安全团队    Tags:Android开发   点击:(66)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条