Android自定义控件——点赞效果(仿Twitter)
来源:互联网 发布:知乎手机版怎么收藏 编辑:程序博客网 时间:2024/06/15 01:14
前言
通过自定义控件,意欲模仿Twitter的点赞效果。
主要涉及:
1.三次贝塞尔曲线应用;
2.属性动画的综合应用;
3.自定义View流程.
拆解原效果
我们先看一下Twitter上的原版效果是怎样的.
放大后:
好吧!原速的看不太清楚,逐帧延迟后:
因为这个效果有需要使用多个动画杂糅而成,为了更确切得出每个子动画阶段所占比例还是用PS大法把它打开,根据该阶段的帧数以及总帧数来确定动画时长如何分配。
实现
1.动画控制
这里使用ValueAnimator并设置插值器为LinearInterpolator来获得随时间正比例变化的逐渐增大的整数值。这个整数值在这里有三个作用。
- 每监听到一个整数值变化重绘一次View.
- 根据整数值的大小范围来划分所处的不同阶段,这里共划分为五个状态.
- 绘制心形并伴随缩小和颜色渐变.
- 绘制圆并伴随放大和颜色渐变.
- 绘制圆环并伴随放大和颜色渐变.
- 圆环减消失、心形放大、周围环绕十四圆点.
- 环绕的十四圆点向外移动并缩小、透明度渐变、渐隐.
- 以整数值为基础来实现其他动画效果避免出现大量的ObjectAnimator.
/** * 展现View点击后的变化效果 */ private void startViewMotion() { if (animatorTime != null && animatorTime.isRunning()) return; resetState(); animatorTime = ValueAnimator.ofInt(0, 1200); animatorTime.setDuration(mCycleTime); animatorTime.setInterpolator(new LinearInterpolator());//需要随时间匀速变化 animatorTime.start(); animatorTime.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int animatedValue = (int) animation.getAnimatedValue(); if (animatedValue == 0) { if (animatorArgb == null || !animatorArgb.isRunning()) { animatorArgb = ofArgb(mDefaultColor, 0Xfff74769, 0Xffde7bcc); animatorArgb.setDuration(mCycleTime * 28 / 120); animatorArgb.setInterpolator(new LinearInterpolator()); animatorArgb.start(); } } else if (animatedValue <= 100) { float percent = calcPercent(0f, 100f, animatedValue); mCurrentRadius = (int) (mRadius - mRadius * percent); if (animatorArgb != null && animatorArgb.isRunning()) mCurrentColor = (int) animatorArgb.getAnimatedValue(); mCurrentState = HEART_VIEW; invalidate(); } else if (animatedValue <= 280) { float percent = calcPercent(100f, 340f, animatedValue);//此阶段未达到最大半径 mCurrentRadius = (int) (2 * mRadius * percent); if (animatorArgb != null && animatorArgb.isRunning()) mCurrentColor = (int) animatorArgb.getAnimatedValue(); mCurrentState = CIRCLE_VIEW; invalidate(); } else if (animatedValue <= 340) { float percent = calcPercent(100f, 340f, animatedValue);//半径接上一阶段增加,此阶段外环半径已经最大值 mCurrentPercent = 1f - percent + 0.2f > 1f ? 1f : 1f - percent + 0.2f;//用于计算圆环宽度,最小0.2,与动画进度负相关 mCurrentRadius = (int) (2 * mRadius * percent); if (animatorArgb != null && animatorArgb.isRunning()) mCurrentColor = (int) animatorArgb.getAnimatedValue(); mCurrentState = RING_VIEW; invalidate(); } else if (animatedValue <= 480) { float percent = calcPercent(340f, 480f, animatedValue);//内环半径增大直至消亡 mCurrentPercent = percent; mCurrentRadius = (int) (2 * mRadius);//外环半径不再改变 mCurrentState = RING_DOT__HEART_VIEW; invalidate(); } else if (animatedValue <= 1200) { float percent = calcPercent(480f, 1200f, animatedValue); mCurrentPercent = percent; mCurrentState = DOT__HEART_VIEW; if (animatedValue == 1200) { animatorTime.cancel(); animatorTime.removeAllListeners(); state = true; } invalidate(); } } }); }
2.图形绘制
心形
这里使用贝塞尔曲线来绘制心形,通过四组控制点的改变来拟合心形。当然项目中为了方便此处的绘制可以用图片代替。
//绘制心形 private void drawHeart(Canvas canvas, int radius, int color) { initControlPoints(radius); mPaint.setColor(color); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); Path path = new Path(); path.moveTo(tPointB.x, tPointB.y); path.cubicTo(tPointC.x, tPointC.y, rPointA.x, rPointA.y, rPointB.x, rPointB.y); path.cubicTo(rPointC.x, rPointC.y, bPointC.x, bPointC.y, bPointB.x, bPointB.y); path.cubicTo(bPointA.x, bPointA.y, lPointC.x, lPointC.y, lPointB.x, lPointB.y); path.cubicTo(lPointA.x, lPointA.y, tPointA.x, tPointA.y, tPointB.x, tPointB.y); canvas.drawPath(path, mPaint); }
其他
还有一些 圆、圆点、圆环的绘制比较简单这里不再列出,重点是这些图形叠加交错的动画变化。
3.点击事件
对外提供点击事件监听,以便处理点赞与取消点赞的逻辑。
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: if (x + getLeft() < getRight() && y + getTop() < getBottom()) {//点击在View区域内 if (state) { deselectLike(); } else { startViewMotion(); } if (mListener != null) mListener.onClick(this); } break; } return true; }
对外提供设置监听的方法
@Override public void setOnClickListener(@Nullable OnClickListener l) { mListener = l; }
获取是否已点赞的状态
/** * Indicates whether this LikeView is selected or not. * * @return true if the LikeView is selected now, false is deselected */ public boolean getState() { return this.state; }
4.最终效果
总结
这里大致实现了Twitter的点赞效果。虽然是根据原效果图像帧比例来确定动画应分配时间的,放慢观察似乎还是不太理想。另有些状态确定不了是颜色渐变还是透明度变化,临界消失时缩放有没有伴随移动,这些都从简处理了。
需要强调一下的是这里用到了颜色渐变动画,而这个方法系统是API21才提供的,
这里直接拷贝系统源码的ArgbEvaluator到项目里了,其实就相当于属性动画自定义TypeEvaluator,既然源码里有,就不客气了。
源码:https://github.com/qkxyjren/LikeView
欢迎指正
阅读全文
2 0
- Android自定义控件——点赞效果(仿Twitter)
- 自定义控件 | 仿《最美有物》点赞效果
- Android自定义控件--仿 path 效果 ArcMenu
- 自定义View-仿即刻点赞效果
- Android自定义控件—仿仪表盘进度控件ArcProgressBar
- 【Android自定义控件】圆圈交替,仿progress效果
- Android 自定义控件 仿MX 播放器的SeekBar效果
- Android自定义View—仿雷达扫描效果
- Android自定义控件——仿ios开关按钮
- Android自定义控件——仿ios开关按钮
- Android自定义控件——仿ios开关按钮
- Android自定义控件——仿ios开关按钮
- 自定义控件—仿IOS7适用于Android的滑动开关
- 自定义控件——圆形圆点进度条(仿安全卫士中的一键加速)
- [Android]仿Periscope点赞效果,显示爱心
- Android动画效果(二) 仿QQ点赞动画
- 【Android开发:自定义控件系列一】仿android4.0 Spinner下拉效果
- 【Android开发:自定义控件系列一】仿android4.0 Spinner下拉效果
- android视频采集YUV420旋转角度算法
- 494. Target Sum
- 翻译的一篇关于学习编程语言的小文章
- trinity运行原理及常见报错(四)
- JSP 调试
- Android自定义控件——点赞效果(仿Twitter)
- icon、png网页开发中所需要的小图标
- HDU 1027 Ignatius and the Princess II (模拟题)
- Python学习之旅-8
- 名字与地址转换 (gethostbyname、getservbyname、getaddrinfo、getnameinfo等)
- 智能硬件的时代,嵌入式是否已经日薄西山
- 计算机CPU核与线程
- linux压缩打包等
- class<T>和 class<?>类型 有什么区别