贝萨尔曲线实现Periscope心形点赞动画效果
先来个效果图
这个动画效果主要几个关注点是:
一、自定义的RelativeLayout中动态加载ImageView
二、刚开始的三个还没移动的动画效果anpha和scaleX,scaleY ,用ObjectAnimator加载
三、红心移动效果,运用了ValueAnimator的TypeEvalutors(估值器) 和addUpdateListener监听,在TypeEvalutors获取了贝塞尔曲线运动时所随机移动的每一个PointF,
然后在监听中获取这个PointF,赋值给imageView的对象,这样就实现了imageView的对象不的x,y坐标不停的改变,实现移动效果
四、最后,在动画结束后remove(imageView)移除对象
详细代码:
先来个layout的xml
- <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”
- xmlns:tools=”http://schemas.android.com/tools”
- android:layout_width=”match_parent”
- android:layout_height=”match_parent”
- android:paddingBottom=”@dimen/activity_vertical_margin”
- android:paddingLeft=”@dimen/activity_horizontal_margin”
- android:paddingRight=”@dimen/activity_horizontal_margin”
- android:paddingTop=”@dimen/activity_vertical_margin”
- tools:context=”.MainActivity” >
- <Button
- android:id=”@+id/button1”
- android:layout_width=”wrap_content”
- android:layout_height=”wrap_content”
- android:layout_alignParentLeft=”true”
- android:layout_alignParentTop=”true”
- android:text=”开始”
- android:onClick=”startClick”/>
- <com.example.test_periscopedemo.MyLayout
- android:id=”@+id/myLayout”
- android:layout_width=”300dp”
- android:layout_height=”300dp”
- android:layout_below=”@id/button1”
- android:background=”@android:color/holo_green_light”
- />
- </RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" ><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_alignParentTop="true"android:text="开始" android:onClick="startClick"/><com.example.test_periscopedemo.MyLayout android:id="@+id/myLayout"android:layout_width="300dp"android:layout_height="300dp"android:layout_below="@id/button1"android:background="@android:color/holo_green_light"/></RelativeLayout>
主Activity:
- package com.example.test_periscopedemo;
- import android.os.Bundle;
- import android.app.Activity;
- import android.view.Menu;
- import android.view.View;
- public class MainActivity extends Activity {
- MyLayout myLayout;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- myLayout = (MyLayout) findViewById(R.id.myLayout);
- }
- public void startClick(View view){
- myLayout.addLayout();
- }
- }
package com.example.test_periscopedemo;import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;public class MainActivity extends Activity {MyLayout myLayout;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myLayout = (MyLayout) findViewById(R.id.myLayout);}public void startClick(View view){myLayout.addLayout();}}
自定义的 RelativeLayout,这个主要的实现类
- package com.example.test_periscopedemo;
- import java.util.Random;
- import android.animation.Animator;
- import android.animation.AnimatorListenerAdapter;
- import android.animation.AnimatorSet;
- import android.animation.ObjectAnimator;
- import android.animation.ValueAnimator;
- import android.animation.ValueAnimator.AnimatorUpdateListener;
- import android.content.Context;
- import android.graphics.BitmapFactory;
- import android.graphics.PointF;
- import android.graphics.drawable.Drawable;
- import android.util.AttributeSet;
- import android.view.View;
- import android.view.animation.AnimationSet;
- import android.widget.ImageView;
- import android.widget.RelativeLayout;
- public class MyLayout extends RelativeLayout{
- Random random;
- Drawable blue,red,yellow;
- LayoutParams lp;
- int dWidth,dHeight;
- int mWidth,mHeight;
- Drawable[] drawables = new Drawable[3];
- public MyLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- mWidth = getMeasuredWidth();
- mHeight = getMeasuredHeight();
- }
- private void init() {
- dWidth = BitmapFactory.decodeResource(getResources(), R.drawable.pl_blue).getWidth();
- dHeight = BitmapFactory.decodeResource(getResources(), R.drawable.pl_blue).getHeight();
- random = new Random();
- blue = getResources().getDrawable(R.drawable.pl_blue);
- red = getResources().getDrawable(R.drawable.pl_red);
- yellow = getResources().getDrawable(R.drawable.pl_yellow);
- drawables[0] = blue;
- drawables[1] = red;
- drawables[2] = yellow;
- lp = new LayoutParams(dWidth, dHeight);
- lp.addRule(CENTER_HORIZONTAL, TRUE); // 这里的TRUE 要注意 不是true
- lp.addRule(ALIGN_PARENT_BOTTOM, TRUE);
- }
- public void addLayout(){
- ImageView iv =new ImageView(getContext());
- iv.setLayoutParams(lp);
- addView(iv);
- iv.setImageDrawable(drawables[random.nextInt(3)]);
- getAnimator(iv);
- }
- private void getAnimator(final View iv){
- ValueAnimator va = ValueAnimator.ofObject(new BezierEvaluator(new PointF(mWidth/2-dWidth/2,mHeight-dHeight), getPointF()), new PointF(
- (mWidth - dWidth) / 2, mHeight - dHeight),
- new PointF(random.nextInt(getWidth()), 0));// 随机
- va.addUpdateListener(new AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- PointF pointF = (PointF) animation.getAnimatedValue();
- iv.setX(pointF.x);
- iv.setY(pointF.y);
- // 这里偷个懒,顺便做一个alpha动画,这样alpha渐变也完成啦
- iv.setAlpha(1 - animation.getAnimatedFraction());
- }
- });
- ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, ”alpha”, 0.2f,1.0f);
- ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, ”scaleX”, 0.2f,1.0f);
- ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, ”scaleY”, 0.2f,1.0f);
- AnimatorSet set = new AnimatorSet();
- set.setDuration(3000);
- set.playTogether(alpha,scaleX,scaleY);
- set.play(va).after(alpha);
- set.setTarget(iv);
- set.addListener(new AnimatorListenerAdapter(){
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- System.out.println(”结束”);
- removeView(iv);
- }
- });
- set.start();
- }
- private PointF getPointF(){
- PointF p = new PointF();
- p.x = random.nextInt(mWidth);
- p.y = 50;
- return p;
- }
- }
package com.example.test_periscopedemo;import java.util.Random;import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AnimationSet;
import android.widget.ImageView;
import android.widget.RelativeLayout;public class MyLayout extends RelativeLayout{Random random;Drawable blue,red,yellow;LayoutParams lp;int dWidth,dHeight;int mWidth,mHeight;Drawable[] drawables = new Drawable[3];public MyLayout(Context context, AttributeSet attrs) {super(context, attrs);init();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);mWidth = getMeasuredWidth();mHeight = getMeasuredHeight();}private void init() {dWidth = BitmapFactory.decodeResource(getResources(), R.drawable.pl_blue).getWidth();dHeight = BitmapFactory.decodeResource(getResources(), R.drawable.pl_blue).getHeight();random = new Random();blue = getResources().getDrawable(R.drawable.pl_blue);red = getResources().getDrawable(R.drawable.pl_red);yellow = getResources().getDrawable(R.drawable.pl_yellow);drawables[0] = blue;drawables[1] = red;drawables[2] = yellow;lp = new LayoutParams(dWidth, dHeight);lp.addRule(CENTER_HORIZONTAL, TRUE); // 这里的TRUE 要注意 不是truelp.addRule(ALIGN_PARENT_BOTTOM, TRUE);}public void addLayout(){ImageView iv =new ImageView(getContext());iv.setLayoutParams(lp); addView(iv); iv.setImageDrawable(drawables[random.nextInt(3)]);getAnimator(iv);}private void getAnimator(final View iv){ ValueAnimator va = ValueAnimator.ofObject(new BezierEvaluator(new PointF(mWidth/2-dWidth/2,mHeight-dHeight), getPointF()), new PointF((mWidth - dWidth) / 2, mHeight - dHeight),new PointF(random.nextInt(getWidth()), 0));// 随机 va.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {PointF pointF = (PointF) animation.getAnimatedValue();iv.setX(pointF.x);iv.setY(pointF.y);// 这里偷个懒,顺便做一个alpha动画,这样alpha渐变也完成啦iv.setAlpha(1 - animation.getAnimatedFraction());}}); ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 0.2f,1.0f); ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX", 0.2f,1.0f);ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY", 0.2f,1.0f);AnimatorSet set = new AnimatorSet();set.setDuration(3000);set.playTogether(alpha,scaleX,scaleY);set.play(va).after(alpha);set.setTarget(iv);set.addListener(new AnimatorListenerAdapter(){@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);System.out.println("结束");removeView(iv);}});set.start();}private PointF getPointF(){PointF p = new PointF();p.x = random.nextInt(mWidth);p.y = 50;return p;}}
自定义的TypeEvaluator类,根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,即在动画执行的不同的时间,返回不同的值,就在这利用贝塞尔曲线工式,获取一个随机移动的点的坐标做为返回值
- package com.example.test_periscopedemo;
- import android.animation.TypeEvaluator;
- import android.graphics.PointF;
- //我们自定义一个BezierEvaluator 实现 TypeEvaluator
- //由于我们view的移动需要控制x y 所以就传入PointF 作为参数,是不是感觉完全契合??
- public class BezierEvaluator implements TypeEvaluator<PointF> {
- private PointF pointF1;//途径的两个点
- private PointF pointF2;
- public BezierEvaluator(PointF pointF1,PointF pointF2){
- this.pointF1 = pointF1;
- this.pointF2 = pointF2;
- System.out.println(”p1=”+pointF1);
- System.out.println(”p2=”+pointF2);
- }
- @Override
- public PointF evaluate(float time, PointF startValue,
- PointF endValue) {
- float timeLeft = 1.0f - time;
- PointF point = new PointF();//结果
- PointF point0 = (PointF)startValue;//起点
- PointF point3 = (PointF)endValue;//终点
- System.out.println(”time”+time);
- System.out.println(”p0=”+point0);
- System.out.println(”p3=”+point3);
- //代入公式
- point.x = timeLeft * timeLeft * timeLeft * (point0.x)
- + 3 * timeLeft * timeLeft * time * (pointF1.x)
- + 3 * timeLeft * time * time * (pointF2.x)
- + time * time * time * (point3.x);
- point.y = timeLeft * timeLeft * timeLeft * (point0.y)
- + 3 * timeLeft * timeLeft * time * (pointF1.y)
- + 3 * timeLeft * time * time * (pointF2.y)
- + time * time * time * (point3.y);
- return point;
- }
- }
package com.example.test_periscopedemo;import android.animation.TypeEvaluator;
import android.graphics.PointF;//我们自定义一个BezierEvaluator 实现 TypeEvaluator
//由于我们view的移动需要控制x y 所以就传入PointF 作为参数,是不是感觉完全契合??
public class BezierEvaluator implements TypeEvaluator<PointF> {private PointF pointF1;//途径的两个点 private PointF pointF2;public BezierEvaluator(PointF pointF1,PointF pointF2){this.pointF1 = pointF1;this.pointF2 = pointF2;System.out.println("p1="+pointF1);System.out.println("p2="+pointF2);}@Overridepublic PointF evaluate(float time, PointF startValue,PointF endValue) {float timeLeft = 1.0f - time;PointF point = new PointF();//结果PointF point0 = (PointF)startValue;//起点PointF point3 = (PointF)endValue;//终点System.out.println("time"+time);System.out.println("p0="+point0);System.out.println("p3="+point3);//代入公式 point.x = timeLeft * timeLeft * timeLeft * (point0.x)+ 3 * timeLeft * timeLeft * time * (pointF1.x)+ 3 * timeLeft * time * time * (pointF2.x)+ time * time * time * (point3.x);point.y = timeLeft * timeLeft * timeLeft * (point0.y)+ 3 * timeLeft * timeLeft * time * (pointF1.y)+ 3 * timeLeft * time * time * (pointF2.y)+ time * time * time * (point3.y);return point;}
}
全部完成
贝萨尔曲线实现Periscope心形点赞动画效果相关推荐
- html怎么显示一个点赞的心形,jquery心形点赞关注效果的简单实现
html代码 css代码 .heart { width: 100px; height: 100px; background: url("") no-repeat; backgrou ...
- iOS 直播心形点赞动画
iOS 直播心形点赞动画 https://github.com/KKKiller/KKHeartFlyAnimation
- [deviceone开发]-心形点赞动画示例
一.简介 这个示例展示do_Animator组件的简单使用,通过点击"点赞"按钮,不断弹出心形图片,向上动画漂移到顶部消失.间隔时间和上下左右移动的步长都是一定范围的随机值. 二. ...
- 微信小程序心形点赞效果
微信小程序心形点赞效果 前言 准备 实现 原理 布局 样式 逻辑实现 尾巴 前言 之前写过一篇文章微信小程序Canvas绘图API,简单介绍了下微信小程序(下面统称小程序)Canvas绘图相关API的 ...
- html+js画一颗心形,用SVG和Vanilla JS框架创建一个“星形变心形”的动画效果
在我写的这篇文章中, 讲述了如何用Vanilla JavaScript使动画顺滑的从一种状态过渡到另一种.最好先看下那篇文章,因为在这篇文章中我们要用到一些那篇文章中讲过的内容.例如例子的演示.各种时 ...
- python绘制立体心形折纸图解_PS制作超漂亮的立体的心形折纸效果
今天为大家分享PS制作超漂亮的立体的心形折纸效果方法,教程难度不是很大,制作出来的折纸效果非常漂亮,好了,一起来学习吧! 背景选择灰色的渐变底 如下 新建一个图层,可以使用其他的图案 或者 图形 但是 ...
- android炫酷动画代码,Android高级UI特效仿直播点赞动画效果
Android高级UI特效仿直播点赞动画效果 发布时间:2020-10-02 16:06:18 来源:脚本之家 阅读:117 作者:mrr 本文给大家分享高级UI特效仿直播点赞效果-一个优美炫酷的点赞 ...
- 用SVG和Vanilla JS框架创建一个“星形变心形”的动画效果
在我写的这篇文章中, 讲述了如何用Vanilla JavaScript使动画顺滑的从一种状态过渡到另一种.最好先看下那篇文章,因为在这篇文章中我们要用到一些那篇文章中讲过的内容.例如例子的演示.各种时 ...
- html5点赞按钮特效,jquery仿直播app按钮点赞动画效果
特效描述:直播app按钮 按钮点赞动画 点赞动画效果.仿照直播软件制作的飘赞效果,jquery点赞动画效果. 代码结构 1. 引入JS 2. HTML代码 $(function () { $(&quo ...
最新文章
- C++ cin.ignore()用法
- UIScrollView用法
- 微服务架构下,静态数据通用缓存机制!
- iOS 深拷贝和浅拷贝
- 编写高质量的代码,改善c#程序的157个建议_之1~10
- php 实时更新内容_亿级视频内容如何实时更新?优酷视频背后的技术揭秘
- 三菱plcfx5u指令手册_从西门子200的PLC程序来看三菱FX5U的PLC程序
- mysql导入报编码错误问题解决
- docker container
- tomcat7 java_java开发环境配置(windows下JDK7+tomcat7)
- Opencv学习笔记(2)模块,图像读取、显示、叠加、融合、颜色分离、亮度、对比度
- 2022华为软挑成功退赛奖
- c语言数码管显示小数点,8位数码管显示正整数和小数及解决鬼影问题
- 我靠跨境电商5个月全款买房:那个你看不起的行业,未来十年最赚钱!
- EasyExcel代码层面设置写出的Excel样式、以及拦截器策略的使用、自动列宽设置、EasyExcel默认设置详解
- 店盈通带你看拼多多开店怎样让排名靠前?
- UC如被百度控股,手机qq浏览器改如何进攻和防守
- vim中Ctrl+t和Ctrl+o快捷键的区别
- UE4官网教程 风格化效果
- Python 的scikit-learn和tensorflow在虚拟环境下安装配置笔记