- 本文已授权微信公众号: 鸿洋 (hongyangAndroid) 原创首发
最近把公司智能家具类的应用中的一个负离子净化显示的控件重写了,干脆就封装了一下起个高大上的名字空气净化器控件,感觉比负离子净化牛逼一点,好像最近锤子也发布了一个空气净化器。
再来个动态的(Gif效果好差没办法它限制5M大小了,真实效果:扇叶是减速运动的),还是看后面吧
一共才写了几个篇博客,没经验啊,看了下别人的都写原理什么的,这次就写一下里面相当比较复杂的效果的,其实,,,,没什么复杂的,不知道从何说起捡几个用于的说。
1. 实现的功能 (注意以思路为主)
- 1. 改变上中下字体大小,字体信息
- 2. 背景颜色实现渐变切换
- 3. 实现扇叶无缝开启和关闭,从上次结束的位置开始动画
- 4. 实现颗粒物效果
- 5. 无缝改变扇叶的速度
- 6.实现扇叶的渐变显示,更加真实
2. 实现扇叶的渐变 (类似于真实扇叶的卷起来效果)
扇叶对比
- 简单说下这个的实现,其实实现虚线画圆真心简单两行代码解决。
// kotlin版 java也是一样就是设置一下绘制效果就可以绘制虚线圆val pathEffect = DashPathEffect(floatArrayOf(mPaint.strokeWidth*0.4f,mPaint.strokeWidth),0f)mPaint.pathEffect = pathEffectcanvas.drawCircle(dashedRingCx,dashedRingCy,dashedRingRadius,mPaint)复制代码
- 但是 渐变的怎么绘制呢?上面的方法就不能用了,因为Android绘制渐变的我想到的只有LinearGradient,我说的是一个个绘制渐变,先说下我的方法,LinearGradient需要传入好几个参数其中这里比较重要的就是x0,y0,x1,y1,就是你需要从那个点渐变到那个点,直接再上个图标就是求出图中两个就可以绘制一个渐变的小圆环了,然后怎么绘制一个圆弧了。
// kotlin版 java也是一样 //实现渐变扇叶while (curAngle < 360 - mEachPanAngle) { val x0 = measuredWidth/2f + (Math.cos((curAngle)*Math.PI/180)*(dashedRingRadius-dashedRadiusDiff*0.5)).toFloat() val y0 = measuredHeight/2f + (Math.sin((curAngle)*Math.PI/180)*(dashedRingRadius-dashedRadiusDiff*0.5)).toFloat() val x1 = measuredWidth/2f + (Math.cos((curAngle+mEachPanAngle)*Math.PI/180)*(dashedRingRadius+dashedRadiusDiff*0.5)).toFloat() val y1 = measuredHeight/2f + (Math.sin((curAngle+mEachPanAngle)*Math.PI/180)*(dashedRingRadius+dashedRadiusDiff*0.5)).toFloat() val shader = LinearGradient(x0, y0, x1, y1, Color.parseColor("#22ffffff"), Color.parseColor("#ffffffff"), Shader.TileMode.CLAMP) mPaint.shader = shader canvas?.drawArc(rectF, curAngle, mEachPanAngle, false, mPaint) curAngle = curAngle + mEachPanAngle + mEachPanAngleGap}mPaint.shader = null //记得清除复制代码
3. 实现的渐变背景
这个的实现方法就很多了可以直接属性动画一个起始值一个结束值,设置animator.setEvaluator(ArgbEvaluator()),还有一个就是使用 使颜色渐变更适合人类观感,公式就不写,网上有源码里也有。
4. 实现扇叶无缝开启和关闭
这个动画还是使用属性动画,但注意每次开启和关闭时传入的值,当前值为起始值,结束值为你要到的值,代码其实很简单。
private fun onFanAnim(isOpenFan: Boolean) { if (mJumpAnimator != null && mJumpAnimator!!.isRunning) { mJumpAnimator!!.cancel() } if (isOpenFan) { mJumpAnimator = ObjectAnimator.ofFloat(this,"dashedRadiusDiff",dashedRadiusDiff,mDashedRingWidth) mJumpAnimator!!.interpolator = DecelerateInterpolator() mJumpAnimator!!.addListener(object : Animator.AnimatorListener{ override fun onAnimationRepeat(p0: Animator?) { } override fun onAnimationEnd(p0: Animator?) { if (!isCancelJumpAnim) { mPanListener?.onHasOpen() onRotateAnim() } isCancelJumpAnim = false } override fun onAnimationCancel(p0: Animator?) { isCancelJumpAnim = true } override fun onAnimationStart(p0: Animator?) { } }) mJumpAnimator!!.duration = 2000 } else { mJumpAnimator = ObjectAnimator.ofFloat(this,"dashedRadiusDiff",dashedRadiusDiff,0f) mJumpAnimator!!.interpolator = AccelerateInterpolator() mJumpAnimator!!.addListener(object : Animator.AnimatorListener{ override fun onAnimationRepeat(p0: Animator?) { } override fun onAnimationEnd(p0: Animator?) { if (dashedRadiusDiff == 0f) { mPanListener?.onHasClose() } } override fun onAnimationCancel(p0: Animator?) { } override fun onAnimationStart(p0: Animator?) { } }) mJumpAnimator!!.duration = 1200 } mJumpAnimator!!.start() }复制代码
5. 实现颗粒物效果
这个实现方法非常多我实现方法应该是比较简单的,但效果不是特别符合空气效果,颗粒物实现了两个效果一个随机流动还有一个随着扇叶渐变到,1.无方向浮动是每次刷新都进行加一个随机 -0.5 ~ 0.5数字 2.被设备吸入的效果使用角度增加,半径减小是不是很简单。
- 1.实现颗粒物无方向飘动
- 2.顺时针向圆心运动就是实现被设备吸入效果
6. 无缝改变扇叶的速度 (GIF效果不太好)
这个实现过程更简单了每次改变动画的时间但要记住起点是上一次动画结束点,终点是结束点+360