android短视频开发,实现动态点赞出现的点赞动画
android短视频开发,实现动态点赞出现的点赞动画
一、
1 点击一次会撒出五个随机表情和点击音效;
2 连续点击会连续撒出表情并播放音效;
3 长按会一直撒;
4 连续撒时会出现次数和标语(0-20 鼓励,20-40加油,>40太棒了);
二、实现过程
2.1 外层布局
因为今日头条里面底部评论框和资讯列表页都会有点赞按钮,那么点赞效果的表情机会满屏幕都存在,所以最外层继承了RelativeLayout。然后宽高都设置match_parent。
在点击按钮的时候触发OnTouch事件:
1 | <br> ivThumbBottom.setOnTouchListener( new View.OnTouchListener() {<br> @Override<br> public boolean onTouch(View v, MotionEvent event) {<br> if (event.getAction() == MotionEvent.ACTION_DOWN) {<br> lastDownTime = System.currentTimeMillis();<br> //获取到 x y的坐标来确定动画撒表情的起点<br> x = (int) event.getRawX();<br> y = (int) event.getRawY();<br> Log.i("aaa", (System.currentTimeMillis() - lastDownTime) + "");<br> handler.postDelayed(mLongPressed, 100);<br> }<br> if (event.getAction() == MotionEvent.ACTION_UP) {<br> Log.i("aaa", (System.currentTimeMillis() - lastDownTime) + "");<br> if (System.currentTimeMillis() - lastDownTime < 100) {//判断为单击事件<br> articleThumbRl.setVisibility(View.VISIBLE);<br> articleThumbRl.setThumb(true, x, y, articleThumbRl);<br> handler.removeCallbacks(mLongPressed);<br> } else {//判断为长按事件后松开<br> handler.removeCallbacks(mLongPressed);<br> }<br> }<br> return true;<br> }<br> }); |
其中通过如下方式实现,长按循环撒表情。
1 | <br> final Runnable mLongPressed = new Runnable() {<br> @Override<br> public void run() {<br> articleThumbRl.setVisibility(View.VISIBLE);<br> articleThumbRl.setThumb(x, y, articleThumbRl);<br> handler.postDelayed(mLongPressed, 100);<br> }<br> }; |
2.2 setThumb方法 处理点击事件
1 | public void setThumb(float x, float y, ArticleRl articleThumbRl) {<br> //这里处理音效播放<br> if (mMediaPlayer.isPlaying()) {<br> mMediaPlayer.seekTo(0);//重复点击时,从头开始播放<br> } else {<br> mMediaPlayer.start();<br> }<br> if (System.currentTimeMillis() - lastClickTime > 800) {//单次点击<br> addThumbImage(mContext, x, y, this);<br> lastClickTime = System.currentTimeMillis();<br> for (int i = getChildCount() - 5; i < getChildCount(); i++) {<br> if (getChildAt(i) instanceof ThumbEmoji) {<br> ((ThumbEmoji) getChildAt(i)).setThumb(true, articleThumbRl);<br> }<br> }<br> currentNumber = 0;<br> if (thumbNumber != null) {<br> removeView(thumbNumber);<br> thumbNumber = null;<br> }<br> } else {//连续点击<br> lastClickTime = System.currentTimeMillis();<br> Log.i(TAG, "当前动画化正在执行");<br> addThumbImage(mContext, x, y, this);<br> for (int i = getChildCount() - 5; i < getChildCount(); i++) {<br> if (getChildAt(i) instanceof ThumbEmoji) {<br> ((ThumbEmoji) getChildAt(i)).setThumb(true, articleThumbRl);<br> }<br> }<br> currentNumber++;<br> //这里添加数字连击view<br> LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);<br> DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();<br> layoutParams.setMargins(600, (int) (y) - 300, 0, 150);<br> if (thumbNumber == null) {<br> thumbNumber = new ThumbNumber(mContext);<br> addView(thumbNumber, layoutParams);//第二个参数 让数字连击始终保持在最上层<br> }<br> thumbNumber.setNumber(currentNumber);<br> }<br> } |
其中,数字连击view中的数字有一个颜色渐变和描边效果,颜色渐变用LinearGradient(扔物线课程里面有),描边用重叠绘制方式。
1 | <br>textPaint = new Paint();<br> textPaint.setTextSize(TEXT_SIZE);<br> textPaint.setTextAlign(Paint.Align.LEFT);<br> textPaint.setStrokeWidth(STROKE_WIDTH);<br> textPaint.setStyle(Paint.Style.FILL);<br> textPaint.setTypeface(Typeface.DEFAULT_BOLD);<br> //这里为了做成上面和下面颜色各一半<br> LinearGradient mLinearGradient = new LinearGradient(0, 0, 0, 90f,<br> new int[]{0xFFFF9641, 0xFFFF9641, 0xFFFF9641, 0xFFFF9641, 0xFFff0000, 0xFFff0000},<br> null, Shader.TileMode.CLAMP);<br> textPaint.setShader(mLinearGradient);<br> //描边画笔<br> textPaintStroke = new Paint();<br> textPaintStroke.setColor(Color.BLACK);<br> textPaintStroke.setTextSize(TEXT_SIZE);<br> textPaintStroke.setTextAlign(Paint.Align.LEFT);<br> textPaintStroke.setStrokeWidth(4);<br> textPaintStroke.setStyle(Paint.Style.STROKE);<br> textPaintStroke.setTypeface(Typeface.DEFAULT_BOLD); |
2.3 添加表情的自定义view ThumbEmoji
1 | private void addThumbImage(Context context, float x, float y, ThumbEmoji.AnimatorListener animatorListener) {<br> List<Integer> list = new ArrayList<>();<br> for (int i = 0; i < 8; i++) {<br> list.add(i);<br> }<br> Collections.shuffle(list); //打乱顺序<br> for (int i = 0; i < 5; i++) {<br> LayoutParams layoutParams = new LayoutParams(100, 100);<br> layoutParams.setMargins((int) x, (int) y - 50, 0, 0);<br> ThumbEmoji articleThumb = new ThumbEmoji(context);<br> articleThumb.setEmojiType(list.get(i));<br> articleThumb.setmAnimatorListener(animatorListener);<br> if (getChildCount() > 1)<br> this.addView(articleThumb, getChildCount() - 1, layoutParams);<br> else {<br> this.addView(articleThumb, layoutParams);<br> }<br> }<br> } |
其中这里的addview方法给他设置index为 childcount-1后,就可以让它保持在数字连击view的下方,但是我设置成1会出现bug,的原因我还得再去看看。
1 | <br> if (getChildCount() > 1)<br> this.addView(articleThumb, getChildCount() - 1, layoutParams);<br> else {<br> this.addView(articleThumb, layoutParams);<br> } |
2.4 撒花效果的动画(也就是抛物线动画)的实现
抛物线动画 分为上升和下降两部分,
上升时,x轴匀速左移或右移,y轴减速向上,表情图片宽高从0变到100;
1 | 下降时,x变为1.2倍x,高度变为最高处的0.8,透明度在最后1/8时间段里从1变为0。<br> private void showThumbDownAni(ArticleRl articleThumbRl) {<br> float topX = -(1080 - 200) + (float) ((2160 - 400) * Math.random());<br> float topY = -300 + (float) (-700 * Math.random());<br> //上升动画<br> //抛物线动画 x方向<br> ObjectAnimator translateAnimationX = ObjectAnimator.ofFloat(this, "translationX",<br> 0, topX);<br> translateAnimationX.setDuration(DURATION);<br> translateAnimationX.setInterpolator(new LinearInterpolator());<br> //y方向<br> ObjectAnimator translateAnimationY = ObjectAnimator.ofFloat(this, "translationY",<br> 0, topY);<br> translateAnimationY.setDuration(DURATION);<br> translateAnimationY.setInterpolator(new DecelerateInterpolator());<br> //表情图片的大小变化<br> ObjectAnimator translateAnimationRightLength = ObjectAnimator.ofInt(this, "rightLength",<br> 0, 100, 100, 100, 100, 100);<br> translateAnimationRightLength.setDuration(DURATION);<br> ObjectAnimator translateAnimationBottomLength = ObjectAnimator.ofInt(this, "bottomLength",<br> 0, 100, 100, 100, 100, 100);<br> translateAnimationBottomLength.setDuration(DURATION);<br> translateAnimationRightLength.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {<br> @Override<br> public void onAnimationUpdate(ValueAnimator animation) {<br> invalidate();//ondraw会在什么情况下执行?<br> }<br> });<br> //动画集合<br> AnimatorSet animatorSet = new AnimatorSet();<br> animatorSet.play(translateAnimationX).with(translateAnimationY).with(translateAnimationRightLength).with(translateAnimationBottomLength);<br> //下降动画<br> //抛物线动画,原理:两个位移动画,一个横向匀速移动,一个纵向变速移动,两个动画同时执行,就有了抛物线的效果。<br> ObjectAnimator translateAnimationXDown = ObjectAnimator.ofFloat(this, "translationX", topX, topX * 1.2f);<br> translateAnimationXDown.setDuration(DURATION / 5);<br> translateAnimationXDown.setInterpolator(new LinearInterpolator());<br> ObjectAnimator translateAnimationYDown = ObjectAnimator.ofFloat(this, "translationY", topY, topY * 0.8f);<br> translateAnimationYDown.setDuration(DURATION / 5);<br> translateAnimationYDown.setInterpolator(new AccelerateInterpolator());<br> //透明度<br> ObjectAnimator alphaAnimation = ObjectAnimator.ofFloat(this, "alpha", 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0f);<br> alphaAnimation.setDuration(DURATION / 5);<br> AnimatorSet animatorSetDown = new AnimatorSet();//设置动画播放顺序<br> //播放上升动画<br> animatorSet.start();<br> animatorSet.addListener(new Animator.AnimatorListener() {<br> <br> @Override<br> public void onAnimationEnd(Animator animation) {<br> animatorSetDown.play(translateAnimationXDown).with(translateAnimationYDown).with(alphaAnimation);<br> animatorSetDown.start();<br> }<br> });<br> animatorSetDown.addListener(new Animator.AnimatorListener() {<br> @Override<br> public void onAnimationEnd(Animator animation) {<br> articleThumbRl.removeView(ThumbEmoji.this);<br> mAnimatorListener.onAnimationEmojiEnd();<br> }<br> });<br> } |
以上就是android短视频开发,实现动态点赞出现的点赞动画。 更多内容欢迎关注之后的文章
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现