Android仿百度贴吧顾客端Loading小球

图片 1封面

图片 2

图片 2

前言

选择百度贴吧顾客端的时候发发掘加载的小动画挺有意思的,于是自个儿入手写写看。想上学自定义View以及自定义动画的同伴一定毫无错失哦。
读者对象须求有最焦点的canvas绘图功底,举例画笔Paint的简易利用、Path怎样画直线等简便的操作,不熟练也没提到,下文带大家撸代码的时候会简单来说一下。
此篇文章用到如下知识点:

1)、自定义View的度量 2)、自定义View属性的自定义及运用
3)、帕特h绘制贝塞尔曲线 4)、Canvas的剪裁 5)、用ValueAnimator调控动画
6)、Canvas文字居中

好了,开首正文!

       封面预览

       封面预览

一、筹算干活

图片 4loading小球

直观的看大家要贯彻八个地方1)、波浪动画、不准则的文字(银灰的半个“贴”字)
3)、控件显示部分限制成圆形

1)、波浪动画
要兑现波浪动画,首先要绘制出波浪的模样,其次再让她动起来。波浪线看起来有一点点疑似正弦也许余弦函数,不过Android的Path并不曾提供绘制正余弦图形的函数,然则提供了贰个意义越来越强大的曲线——贝塞尔曲线,贝塞尔曲线分为二阶、三阶及多阶,本案例里使用的是三回贝塞尔曲线,如下图所示,二阶贝塞尔曲线要求四个点才方可明确

图片 5二阶贝塞尔曲线

咱俩来看一下Android里贝塞尔曲线的源码:

/* @param x1 The x-coordinate of the control point on a quadratic curve * @param y1 The y-coordinate of the control point on a quadratic curve * @param x2 The x-coordinate of the end on a quadratic curve * @param y2 The y-coordinate of the end point on a quadratic curve */ public void quadTo(float x1, float y1, float x2, float y2) { isSimplePath = false; native_quadTo(mNativePath, x1, y1, x2, y2); }

由注脚能够看出来quadTo(float x1, float y1, float x2, float y2)的八个参数分别是调节点的x,y坐标,截至点的x,y坐标,少了四个起来点啊!不要发急,起初点是Path路线的上一回截止的点,如果你的Path未有绘制过路径,那么Path的尾声八个点坐标正是只要想本身定义初步点地方,就用Path.moveTo(float x, float y)就可以。但是每一遍都须求钦赐具体的调控点和截止点既麻烦又易于出错,那么就要求rQuadTo(float dx1, float dy1, float dx2, float dy2)出台了,rQuadTo跟quadTo的分化在于rQuadTo使用的是相对开端点的坐标,实际不是现实性的坐标点,举个例证,如下代码效果相当:

 //使用quadTo Path path=new Path(); path.moveTo; path.quadTo(150,0,200,100); //使用rQuadTo Path path=new Path(); path.moveTo; path.rQuadTo(50,-100,100,0);

那时候画笔最终的落点都为。
画波浪线的本事难关化解了那么哪些让波浪动起来吧,想动起来确定要求波浪在档期的顺序方向移动,那么大家必要画三个非常短非常短的浪花让他移动,那样就贯彻了左右起伏效果,可是这么必要画无数多条贝塞尔曲线,料定不行,那时就用到万能的数学理论——周期函数了,尽管大家绘制四个周期的贝塞尔曲线,每一次只让它展现二个周期,然后品级二周期突显停止的时候再从头开头,那样就产生了非常周期的假象,如下图
初步地方为1,向右前进,当走到2地方的时候重新载入参数成3的岗位,即1原来的岗位,如此往复就成了博大精深的浪花了

图片 6绵延原理

做成机能如下:浅绿区域正是要体现的区域,灰绿竖线是波浪线八个周期的总厅长度

图片 7连绵不绝的波浪线

2)、不法则的文字

大家能够看来圆球里的“贴”字在波浪区域呈现的是反动,波浪区域之外显示的是紫酱色,Android并不接济给文字部分区域着色的功用,那么我们只好靠调整展现区域让文字只显示特定形状,庞大的Canvas正好有画布裁剪作用,通过裁剪画布就能够垄断(monopoly)绘制区域,画布的剪裁能够用Canvas.clipPath(Path path)贯彻,传入二个关闭的帕特h不只能够随性所欲裁剪画布,裁剪暗中表示图如下

图片 8剪裁文字

选拔波浪形闭合路径讲画布裁剪成波浪形,那么在此接下去的Canvas绘制操的原委只能在那个波浪形区域里展现,那样就消除了文字的一对区域呈现难点。那么接下去大家只用在同样地点绘制一样字体、字号区别色的文字就可以完毕贰个文字呈现两种颜色了(注意:实操的时候,被裁剪的文字要盖在未被减弱的文字的上方,即先在画布裁剪此前绘制暗黄的“贴”字,然后再裁剪画布再在裁剪后的画布上绘制石黄的“贴”)

**3)、控件突显部分限制作而成圆形 **

经过2)的剖释,将呈现部分限制在圈子区域里不是探囊取物吗,使用多少个圆形的Path裁剪画布就可以。感兴趣的同班也可以尝试BitmapShader或许Xfermode来将展现区域改为圆形

好了,最入眼的步骤都深入分析完了,上一张图越来越直观地出示一下制图流程

图片 9完整分析图

图中得以见见波浪形的闭合Path有四个功能,三个是承担裁剪画布,二个是承受绘制石磨蓝,其实只用第贰个功效就能够,此处只是利于分解步骤。

  前言

  前言

二、代码达成

文章只贴出主要代码,完整代码文末提供链接

既是是自定义控件,这将要有通用性举个例子上边包车型地铁机能:

图片 10各样颜色的球球

loading小球需文字和颜料都得以改造,所以我们要给自个儿的控件加多这四个本性。首先在“res/values/”路线下新建三个attrs.xml文件,在里面定义如下属性:

 <declare-styleable name="Wave"> <attr name="color" format="color"/> <attr name="text" format="string"/> </declare-styleable>

接下去开始自定义View
复写多个构造函数,将单参数和双参数的构造函数的super方法都改为this,保险不管调用哪个构造方法都会跳到四个参数的构造方法中,那样就足以偷懒只用在多个参数的构造方法里开端化各个参数了

public class Wave extends View { public Wave(Context context) { this(context,null); } public Wave(Context context, AttributeSet attrs) { this(context, attrs,0); } public Wave(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //初始化参数 init(context,attrs); }}

接下去是开首化函数,在那边我们赢获得自定义的颜料及文字参数,并伊始化种种画笔,代码相比轻松,看注释内容就能够

private void init(Context context, AttributeSet attrs) { //获取自定义参数值 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Wave); //自定义颜色和文字 color = array.getColor(R.styleable.Wave_color, Color.rgb(41, 163, 254)); text = array.getString(R.styleable.Wave_text); array.recycle(); //图形及路径填充画笔(抗锯齿、填充、防抖动) mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor; mPaint.setDither; //文字画笔(抗锯齿、白色、粗体) textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); textPaint.setColor(Color.WHITE); textPaint.setTypeface(Typeface.DEFAULT_BOLD); //闭合波浪路径 path = new Path(); }

接下去是生成波浪线的议程,暗示图如下:

图片 11波浪生成原理

将Path起源移动到最侧边米白点处,然后绘制多少个周期的长度的波浪(一上一下是三个周期),种种周期在x轴的跨度为此控件的宽窄调控点距波形的轴线的断然惊人是成套控件的3/20,当然想让波形波幅大的话那个比例能够轻便调度,接下去就用前面讲到的rQuadTo来生成闭合的浪花图形,当中mWidth为控件的升幅,mHeight为控件的冲天

 private Path getActionPath(float percent) { Path path = new Path(); int x = -mWidth; //当前x点坐标(根据动画进度水平推移,一个动画周期推移的距离为一个周期的波长) x += percent * mWidth; //波形的起点 path.moveTo(x, mHeight / 2); //控制点的相对宽度 int quadWidth = mWidth / 4; //控制点的相对高度 int quadHeight = mHeight / 20 * 3; //第一个周期波形 path.rQuadTo(quadWidth, quadHeight, quadWidth * 2, 0); path.rQuadTo(quadWidth, -quadHeight, quadWidth * 2, 0); //第二个周期波形 path.rQuadTo(quadWidth, quadHeight, quadWidth * 2, 0); path.rQuadTo(quadWidth, -quadHeight, quadWidth * 2, 0); //右侧的直线 path.lineTo(x + mWidth * 2, mHeight); //下边的直线 path.lineTo(x, mHeight); //自动闭合补出左边的直线 path.close(); return path; }

下边代码所表示的关闭路线如下图

图片 12关闭的波浪图形

接下去就是重头戏onDraw了

 @Override protected void onDraw(Canvas canvas) { //底部的字 textPaint.setColor; drawCenterText(canvas, textPaint, text); //上层的字 textPaint.setColor(Color.WHITE); //生成闭合波浪路径 path = getActionPath(currentPercent); canvas.clipPath; //裁剪成圆形 canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mPaint); drawCenterText(canvas, textPaint, text); }

此间绘制思路是:在canvas上绘制洋红的文字 ——>将画布裁剪成波浪形
——>在波浪形画布上制图圆
——>在波浪形画布上制图像和文字字,这里一定要留神绘制顺序,先绘制的在下边,后绘制的在上部。
留神的朋友一定看到了二个函数drawCenterText(canvas, textPaint, text)科学,那个函数就是讲文字绘于控件正着力的方法。有的读者恐怕直接在使用Canvas.drawText( String text, float x, float y, Paint paint)
那些主意,然则参数中的到底是哪些坐标呢,是文字左上角的点的坐标吗?不是的,接下去大家用代码验证一下以此到底在文字的哪些部位

 canvas.drawText(text,600,200,textPaint); canvas.drawCircle(600,200,3,paint); canvas.translate; Rect bgRect=new Rect(0,0,1000,400); canvas.drawRect(bgRect,bgPaint); Rect textBound=new Rect();textPaint.getTextBounds(text,0,text.length(),textBound); paint.setColor(Color.RED); canvas.drawRect(textBound,paint); Paint.FontMetrics metrics=textPaint.getFontMetrics(); paint.setColor(Color.RED); // ascent 橙色 paint.setColor(Color.rgb(255,126,0)); canvas.drawLine(0, metrics.ascent, 500,metrics.ascent, paint); // descent paint.setColor(Color.rgb(255,0,234)); canvas.drawLine(0, metrics.descent, 500, metrics.descent, paint); // top paint.setColor(Color.DKGRAY); canvas.drawLine(0, metrics.top, 500, metrics.top, paint); // bottom paint.setColor(Color.GREEN); canvas.drawLine(0, metrics.bottom, 500, metrics.bottom, paint);

首先是在画布的处画上文字,为了方便观看在文字的什么样地点,作者在处画了叁个半径3像素的圈子。然后平移画布到的地方然后逐一画出了文字的边框图以及FontMetrics新闻里的top、ascent、descent、bottom音讯小编把运转结果截图做了管理,方便我们看

图片 13文字的各种边界
从结果看那多少个白灰的点并非在文字的左上角,而是左下角,这些点所在的y坐标就是大家常说的BaseLine的地点,那今后以此函数Canvas.drawText( String text, float x, float y, Paint paint)就足以知道为——将文字的基准点放在处,那么那一个基准点能够变动呢?答案是自然的,可以经过绘制文字的画笔的setTextAlign(Align align)方法设置为Paint.Align.CENTE瑞虎恐怕Paint.Align.TucsonIGHT,即便不安装的话暗许是Paint.阿里gn.LEFT。读者朋友们有意思味的话能够试试设置成CENTE中华V之后的蓝圈圈是或不是跑到了文字的中部呢?从上图大家也得以见见,整个文字是在乎FontMetrics.topFontMetrics.bottom中间。
好了,贴上文字居中的代码,相信认真看下边这段话的相恋的人肯定能自在读懂

 private void drawCenterText(Canvas canvas, Paint textPaint, String text) { Rect rect = new Rect(0, 0, mWidth, mHeight); textPaint.setTextAlign(Paint.Align.CENTER); Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); //文字框最高点距离baseline的距离 float top = fontMetrics.top; //文字框最低点距离baseline的距离 float bottom = fontMetrics.bottom; int centerY =  (rect.centerY() - top / 2 - bottom / 2); canvas.drawText(text, rect.centerX(), centerY, textPaint); }

剖判好下面的代码
大家就能够绘制出二个静态的小球了,动画既然要动,料定就疑似轿车同样需求二个”引擎”,在地点聊到的绘图波浪路线的函数中大家忽视了getActionPath(float percent)的参数percent,这几个参数便是当前卡通的速度,那么我们怎么来制作这几个速度呢?必要什么样把那几个动画“引擎”激起呢。我们得以经过种种手腕计时,生成二个计时Thread大概本人写一个Handler等等,只要能均匀的成形进程就可以。
本文中用到一个精美绝伦的机械漏刻ValueAnimator
我们常说的属性动画ObjectAnimator正是它的二个子类,使用它来作为动画的引擎再实惠可是了,从字面翻译”ValueAnimator”那正是“值动画者”直译纵然low然则恰恰更加好驾驭,正是让数值动起来,从什么值动到怎么值吗?ValueAnimator animator = ValueAnimator.ofFloat;那句话正是概念叁个值从0变化到1的多少个animator,大家的percent值就是从0变化到1的中间进程值,那么怎么得到那一个历程值吗?——监听器!对!

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float percent = animation.getAnimatedFraction;

那就是说数值从0变到1亟待多短时间呢?怎么能Infiniti重复呢?重复的时候是重头起头依旧反转举行呢?别急上边三句话正是让动画片Infiniti重复,每趟从头开端,二个周期1000微秒

 animator.setDuration; animator.setRepeatCount(ValueAnimator.INFINITE); animator.setRepeatMode(ValueAnimator.RESTART);

好了,引擎设置好了,发动

animator.start();``` 上效果![鬼畜版](http://upload-images.jianshu.io/upload_images/2198310-0a96a326b00ffd2f?imageMogr2/auto-orient/strip)WTF!这是什么鬼,为什么鬼畜地慢几拍?打印出来横坐标看看

07-09 18:18:47.308 E/Jcs: getActionPath: -2107-09 18:18:47.326 E/Jcs:
getActionPath: -1507-09 18:18:47.342 E/Jcs: getActionPath: -1007-09
18:18:47.359 E/Jcs: getActionPath: -507-09 18:18:47.375 E/Jcs:
getActionPath: -207-09 18:18:47.392 E/Jcs: getActionPath: 007-09
18:18:47.409 E/Jcs: getActionPath: 0

最后几拍的数值差好像不太对呀!拍拍脑门突然一想,我的动画不均匀是忘记设置一个均匀的插值器了!哎!

animator.setInterpolator(new LinearInterpolator;

补上一个线性插值器,整个世界都顺畅了![感谢女朋的默默支持](http:https://upload-images.jianshu.io/upload_images/2198310-aed11f4c0a379621?imageMogr2/auto-orient/strip) [百度Loading小球Github源码](https://github.com/Jichensheng/BaiduWave)###三、结语第一次写文章,不免有些疏漏之处,望多多指教!后续我会不定期更新新的内容,争取把写文章当成自己生活的一部分。 ---### 后记(2017年7月27日15:02:39) 有不少读者问到关于小球和边缘锯齿的问题,我分别用如下方式实现loading小球 > 1、Canvas的clip方式限制波浪边界2、使用Xfermode方式限制波浪和圆形的边界3、用Xfermode方式限制白色文字,用shader方式限制圆形的边界 下边是效果预览图,代码已经提交到[github](https://github.com/Jichensheng/BaiduWave)上了,讲解部分尽快补到此文中![三种方式对比](http://upload-images.jianshu.io/upload_images/2198310-4f372d9dd92b1a93.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

  使用百度贴吧顾客端的时候发开采加载的小动画挺有意思的,于是自个儿入手写写看。想深造自定义View以及自定义动画的伙伴一定不要错过哦。

  使用百度贴吧客商端的时候发发掘加载的小动画挺风趣的,于是自身入手写写看。想上学自定义View以及自定义动画的小同伴一定毫无错失哦。

  读者对象需求有最大旨的canvas绘图功底,举例画笔Paint的粗略利用、Path怎么样画直线等轻便的操作,面生也没提到,下文带大家撸代码的时候会一句话来讲一下。

  读者对象供给有最主题的canvas绘图功底,比如画笔Paint的简易利用、Path如何画直线等简便的操作,不熟习也没提到,下文带大家撸代码的时候会简来说之一下。

  此篇作品用到如下知识点:

  此篇小说用到如下知识点:

  • 1)、自定义View的测量
  • 1)、自定义View的测量

 

 

  • 2)、自定义View属性的自定义及运用
  • 2)、自定义View属性的自定义及应用

 

 

  • 3)、帕特h绘制贝塞尔曲线
  • 3)、Path绘制贝塞尔曲线

 

 

  • 4)、Canvas的裁剪
  • 4)、Canvas的裁剪

 

 

  • 5)、用ValueAnimator调控动画
  • 5)、用ValueAnimator调整动画

 

 

  • 6)、Canvas文字居中
  • 6)、Canvas文字居中

 

 

  好了,先河正文!

  好了,初叶正文!

  一、准备干活

  一、筹划干活

  1、效果图

  1、效果图

图片 14

图片 14

loading小球

loading小球

  2、动画拆解

  2、动画拆解

  直观的看大家要完毕八个地点

  直观的看我们要落到实处几个方面

  1)、波浪动画(杏黄部分)

  1)、波浪动画(海水绿部分)

  2)、不法规的文字(浅绛红的半个“贴”字)

  2)、不准则的文字(驼色的半个“贴”字)

  3)、控件彰显部分限制作而成圆形

  3)、控件展现部分限制作而成圆形

  3、手艺解析

  3、技能深入分析

  1)、波浪动画

  1)、波浪动画

  要贯彻波浪动画,首先要绘制出波浪的形象,其次再让他动起来。波浪线看起来有一点点疑似正弦或然余弦函数,然则Android的Path并不曾提供绘制正余弦图形的函数,可是提供了贰个意义更加强硬的曲线——贝塞尔曲线,贝塞尔曲线分为二阶、三阶及多阶,本案例里使用的是三遍贝塞尔曲线,如下图所示,二阶贝塞尔曲线须求多个点才方可鲜明

  要兑现波浪动画,首先要绘制出波浪的形象,其次再让他动起来。波浪线看起来有一点疑似正弦也许余弦函数,但是Android的Path并未提供绘制正余弦图形的函数,可是提供了三个职能更庞大的曲线——贝塞尔曲线,贝塞尔曲线分为二阶、三阶及多阶,本案例里使用的是三遍贝塞尔曲线,如下图所示,二阶贝塞尔曲线必要几个点才得以分明

 

 

图片 16

图片 16

二阶贝塞尔曲线

二阶贝塞尔曲线

  我们来看一下Android里贝塞尔曲线的源码:

  大家来看一下Android里贝塞尔曲线的源码:

  1. /* @param x1 The x-coordinate of the control
    point on a quadratic curve
  2. * @param y1 The y-coordinate of the control
    point on a quadratic curve
  3. * @param x2 The x-coordinate of the end on a quadratic curve

  4. * @param y2 The y-coordinate of the end point on a quadratic curve

  5. */

  6. public void quadTo(float
    x1, float y1, float x2,
    float y2) {

  7. isSimplePath = false;

  8. native_quadTo(mNativePath, x1, y1, x2, y2);
  9. }
  1. /* @param x1 The x-coordinate of the control
    point on a quadratic curve
  2. * @param y1 The y-coordinate of the control
    point on a quadratic curve
  3. * @param x2 The x-coordinate of the end on a quadratic curve

  4. * @param y2 The y-coordinate of the end point on a quadratic curve

  5. */

  6. public void quadTo(float
    x1, float y1, float x2,
    float y2) {

  7. isSimplePath = false;

  8. native_quadTo(mNativePath, x1, y1, x2, y2);
  9. }

  由注脚能够看出来quadTo(float x1, float y1, float x2, float
y2)的多少个参数分别是调节点的x,y坐标,截至点的x,y坐标,少了贰个初步点啊!不要焦急,开端点是Path路线的上叁遍甘休的点,固然你的Path未有绘制过路线,那么帕特h的尾声叁个点坐标正是(0,0)借使想协和定义起先点地方,就用帕特h.moveTo(float
x, float y)就可以。

  由注解能够看出来quadTo(float x1, float y1, float x2, float
y2)的八个参数分别是调节点的x,y坐标,甘休点的x,y坐标,少了一个起先点啊!不要焦急,最初点是Path路线的上三遍甘休的点,借让你的Path未有绘制过路线,那么Path的尾声一个点坐标就是(0,0)假如想和谐定义初始点地点,就用Path.moveTo(float
x, float y)就可以。

  可是每趟都急需钦点具体的调整点和截止点既麻烦又便于出错,那么就须要rQuadTo(float
dx1, float dy1, float dx2, float
dy2)出马了,rQuadTo跟quadTo的区别在于rQuadTo使用的是相持开端点的坐标,并不是切实的坐标点,举例,如下代码效果相当于:

  不过每一次都亟需内定具体的调整点和甘休点既麻烦又轻便失误,那么就要求rQuadTo(float
dx1, float dy1, float dx2, float
dy2)出马了,rQuadTo跟quadTo的界别在于rQuadTo使用的是绝对开首点的坐标,并不是切实可行的坐标点,举个例证,如下代码效果格外:

  1. //使用quadTo
  2. Path path=new Path();
  3. path.moveTo(100,100);
  4. path.quadTo(150,0,200,100);
    1. //使用rQuadTo
  5. Path path=new Path();
  6. path.moveTo(100,100);
  7. path.rQuadTo(50,-100,100,0);
  1. //使用quadTo
  2. Path path=new Path();
  3. path.moveTo(100,100);
  4. path.quadTo(150,0,200,100);
    1. //使用rQuadTo
  5. Path path=new Path();
  6. path.moveTo(100,100);
  7. path.rQuadTo(50,-100,100,0);

  此时画笔最终的落点都为(200,100)。

  此时画笔最终的落点都为(200,100)。

  画波浪线的技巧困难解决了那么怎么样让波浪动起来吧,想动起来肯定要求波浪在档案的次序方向移动,那么大家须求画七个十分长十分短的浪花让他活动,那样就实现了内外起伏效果,不过那样要求画无数多条贝塞尔曲线,鲜明非常,那时就用到万能的数学理论——周期函数了,假如大家绘制多个周期的贝塞尔曲线,每趟只让它呈现三个周期,然后等级二周期展现甘休的时候再从头开首,那样就招致了最佳周期的假象,如下图

  画波浪线的手艺困难化解了那么什么样让波浪动起来呢,想动起来自然需求波浪在档案的次序方向移动,那么大家需求画多少个十分长相当长的波浪让她一举手一投足,那样就落实了前后起伏效果,不过这么要求画无数多条贝塞尔曲线,明确极其,那时就用到万能的数学理论——周期函数了,假设我们绘制多个周期的贝塞尔曲线,每趟只让它显得叁个周期,然后等级二周期显示甘休的时候再从头初叶,那样就变成了并世无两周期的假象,如下图

  初步地方为1,向右前进,当走到2任务的时候重新设置成3的任务,即1原有的职位,如此往返就成了绵亘不绝的浪花了

  初步地点为1,向右前进,当走到2地点的时候重新恢复设置成3的地方,即1原始的岗位,如此往返就成了不停不绝的浪花了

 

 

图片 18

图片 18

发表评论

电子邮件地址不会被公开。 必填项已用*标注