Android(安卓)仿直播特效点赞飘爱心
16lz
2021-01-26
一、概述,最后面有完整代码下载地址
老规矩先上图
好了,基本就是这个样子,录完的视频用格式工厂转换完就这个样子了,将就看吧
二、定义我们自己的Layout
[java] view plain copy- /**
- * @author 刘洋巴金
- * @date 2017-4-27
- *
- * 定义我们自己的布局
- * */
- public class LoveLayout extends RelativeLayout{
- private Context context;
- private LayoutParams params;
- private Drawable[] icons = new Drawable[4];
- private Interpolator[] interpolators = new Interpolator[4];
- private int mWidth;
- private int mHeight;
- public LoveLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.context = context;
- initView();
- }
- private void initView() {
- // 图片资源
- icons[0] = getResources().getDrawable(R.drawable.green);
- icons[1] = getResources().getDrawable(R.drawable.purple);
- icons[2] = getResources().getDrawable(R.drawable.red);
- icons[3] = getResources().getDrawable(R.drawable.yellow);
- // 插值器
- interpolators[0] = new AccelerateDecelerateInterpolator(); // 在动画开始与结束的地方速率改变比较慢,在中间的时候加速
- interpolators[1] = new AccelerateInterpolator(); // 在动画开始的地方速率改变比较慢,然后开始加速
- interpolators[2] = new DecelerateInterpolator(); // 在动画开始的地方快然后慢
- interpolators[3] = new LinearInterpolator(); // 以常量速率改变
- int width = icons[0].getIntrinsicWidth();
- int height = icons[0].getIntrinsicWidth();
- params = new LayoutParams(width, height);
- params.addRule(CENTER_HORIZONTAL, TRUE);
- params.addRule(ALIGN_PARENT_BOTTOM, TRUE);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- // TODO Auto-generated method stub
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- mWidth = getMeasuredWidth();
- mHeight = getMeasuredHeight();
- }
- public void addLoveView() {
- // TODO Auto-generated method stub
- final ImageView iv = new ImageView(context);
- iv.setLayoutParams(params);
- iv.setImageDrawable(icons[new Random().nextInt(4)]);
- addView(iv);
- // 开启动画,并且用完销毁
- AnimatorSet set = getAnimatorSet(iv);
- set.start();
- set.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // TODO Auto-generated method stub
- super.onAnimationEnd(animation);
- removeView(iv);
- }
- });
- }
- /**
- * 获取动画集合
- * @param iv
- * */
- private AnimatorSet getAnimatorSet(ImageView iv) {
- // 1.alpha动画
- ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 0.3f, 1f);
- // 2.缩放动画
- ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX", 0.2f, 1f);
- ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY", 0.2f, 1f);
- // 动画集合
- AnimatorSet set = new AnimatorSet();
- set.playTogether(alpha, scaleX, scaleY);
- set.setDuration(500);
- // 贝塞尔曲线动画
- ValueAnimator bzier = getBzierAnimator(iv);
- AnimatorSet set2 = new AnimatorSet();
- set2.playSequentially(set, bzier);
- set2.setTarget(iv);
- return set2;
- }
ObjectAnimator为属性动画,不熟悉可以百度了解下
然后是设置贝塞尔曲线动画
playSequentially:动画依次执行
- /**
- * 贝塞尔动画
- * */
- private ValueAnimator getBzierAnimator(final ImageView iv) {
- // TODO Auto-generated method stub
- PointF[] PointFs = getPointFs(iv); // 4个点的坐标
- BasEvaluator evaluator = new BasEvaluator(PointFs[1], PointFs[2]);
- ValueAnimator valueAnim = ValueAnimator.ofObject(evaluator, PointFs[0], PointFs[3]);
- valueAnim.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- // TODO Auto-generated method stub
- PointF p = (PointF) animation.getAnimatedValue();
- iv.setX(p.x);
- iv.setY(p.y);
- iv.setAlpha(1- animation.getAnimatedFraction()); // 透明度
- }
- });
- valueAnim.setTarget(iv);
- valueAnim.setDuration(3000);
- valueAnim.setInterpolator(interpolators[new Random().nextInt(4)]);
- return valueAnim;
- }
- private PointF[] getPointFs(ImageView iv) {
- // TODO Auto-generated method stub
- PointF[] PointFs = new PointF[4];
- PointFs[0] = new PointF(); // p0
- PointFs[0].x = (mWidth- params.width)/ 2;
- PointFs[0].y = mHeight - params.height;
- PointFs[1] = new PointF(); // p1
- PointFs[1].x = new Random().nextInt(mWidth);
- PointFs[1].y = new Random().nextInt(mHeight /2) + mHeight / 2 + params.height;
- PointFs[2] = new PointF(); // p2
- PointFs[2].x = new Random().nextInt(mWidth);
- PointFs[2].y = new Random().nextInt(mHeight /2);
- PointFs[3] = new PointF(); // p3
- PointFs[3].x = new Random().nextInt(mWidth);
- PointFs[3].y = 0;
- return PointFs;
- }
p0坐标:x坐标((布局的宽-心形图片宽)除以2),y坐标(布局的高 -心形图片高),这样获得的是顶部部水平中心点的坐标。
p1坐标:x坐标(横坐标中的随机位置),y坐标(布局一半的高度 加上 0到一半高度范围内的随机坐标+心形的高度的一半)。这样取到的横坐标是在布局宽度之内的随机坐标,纵坐标为整个路径高度中部以上的随机坐标。
p2坐标:与p1类似,横坐标是在布局宽度之内的随机坐标,纵坐标为整个路径高度中部以下的随机坐标。
p3坐标:控件底部中心点
好了知道4个坐标了,那么开始计算路径
首先为了计算贝塞尔曲线,我们先写一个估值器
[java] view plain copy- /**
- * @author 刘洋巴金
- * @date 2017-4-27
- *
- * 估值器,计算路径
- * */
- public class BasEvaluator implements TypeEvaluator
{ - private PointF p1;
- private PointF p2;
- public BasEvaluator(PointF p1, PointF p2) {
- super();
- this.p1 = p1;
- this.p2 = p2;
- }
- @Override
- public PointF evaluate(float fraction, PointF p0, PointF p3) {
- // TODO Auto-generated method stub
- PointF pointf = new PointF();
- // 贝塞尔曲线公式 p0*(1-t)^3 + 3p1*t*(1-t)^2 + 3p2*t^2*(1-t) + p3^3
- pointf.x = p0.x * (1-fraction) *(1-fraction ) * (1-fraction)
- +3*p1.x * fraction *(1-fraction )*(1-fraction )
- +3*p2.x *fraction *fraction *(1-fraction )
- +p3.x*fraction *fraction *fraction ;
- pointf.y = p0.y * (1-fraction ) *(1-fraction ) * (1-fraction )
- +3*p1.y * fraction *(1-fraction )*(1-fraction )
- +3*p2.y *fraction *fraction *(1-fraction )
- +p3.y*fraction *fraction *fraction ;
- return pointf;
- }
- }
evaluate三个参数:
1.fraction,默认传入的就是(currentTime - startTime) / duration,动画执行的时间除以总的时间比值,可以理解为变化率。当duration到了的时候,正好,起始点变到终点。
2.起始点
3.终点
根据三个参数,计算点的根据每毫秒的变化率,计算点的路径轨迹。
好了贝塞尔曲线动画就讲完了,然后再把动画绑定到控件上。
最后在MainActivity中根据点击事件,进行增加心型就好了。
[java] view plain copy- btn_press = (Button)findViewById(R.id.btn_press);
- ll_love = (LoveLayout)findViewById(R.id.ll_love);
- btn_press.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- ll_love.addLoveView();
- }
- });
完整Demo代码下载地址:Android仿某直播点赞飘爱心
更多相关文章
- Android仿淘宝头条滚动广告条
- Fragment的使用
- Android(安卓)动画之AlphaAnimation应用详解
- Android基础笔记(十)- 帧动画、补间动画具体解释、对话框
- 基于AndroidStudio开发的简单登陆页面制作
- Android学习笔记(三)UI
- Android(安卓)RelativeLayout布局
- Android动画-Interpolator(插值器)大全
- AndroidStudio插件:布局文件转化Databinding