贝萨尔曲线实现Periscope心形点赞动画效果
2016-11-17 19:10
519 查看
先来个效果图
这个动画效果主要几个关注点是:
一、自定义的RelativeLayout中动态加载ImageView
二、刚开始的三个还没移动的动画效果anpha和scaleX,scaleY ,用ObjectAnimator加载
三、红心移动效果,运用了ValueAnimator的TypeEvalutors(估值器) 和addUpdateListener监听,在TypeEvalutors获取了贝塞尔曲线运动时所随机移动的每一个PointF,
然后在监听中获取这个PointF,赋值给imageView的对象,这样就实现了imageView的对象不的x,y坐标不停的改变,实现移动效果
四、最后,在动画结束后remove(imageView)移除对象
详细代码:
先来个layout的xml
[java] view plain copy print?<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>
主Activity:
[java] view plain copy print?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(); } }
自定义的 RelativeLayout,这个主要的实现类
[java] view plain copy print?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;
}
}
自定义的TypeEvaluator类,根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,即在动画执行的不同的时间,返回不同的值,就在这利用贝塞尔曲线工式,获取一个随机移动的点的坐标做为返回值
[java] view plain copy print?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;
}
}
全部完成
这个动画效果主要几个关注点是:
一、自定义的RelativeLayout中动态加载ImageView
二、刚开始的三个还没移动的动画效果anpha和scaleX,scaleY ,用ObjectAnimator加载
三、红心移动效果,运用了ValueAnimator的TypeEvalutors(估值器) 和addUpdateListener监听,在TypeEvalutors获取了贝塞尔曲线运动时所随机移动的每一个PointF,
然后在监听中获取这个PointF,赋值给imageView的对象,这样就实现了imageView的对象不的x,y坐标不停的改变,实现移动效果
四、最后,在动画结束后remove(imageView)移除对象
详细代码:
先来个layout的xml
[java] view plain copy print?<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" > <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>
主Activity:
[java] view plain copy print?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; @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(); } }
自定义的 RelativeLayout,这个主要的实现类
[java] view plain copy print?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(); } @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; } }
自定义的TypeEvaluator类,根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,即在动画执行的不同的时间,返回不同的值,就在这利用贝塞尔曲线工式,获取一个随机移动的点的坐标做为返回值
[java] view plain copy print?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); } @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; } }
全部完成
相关文章推荐
- Android项目开发 教你实现Periscope点赞效果
- 一步一步实现Periscope点赞效果
- Android -- 自定义ViewGroup+贝塞尔+属性动画实现仿QQ点赞效果
- jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
- GoodView实现多种点赞动画效果
- UGUI实现UI精灵由小到大渐变效果——配合unity动画曲线
- jQuery实现的点赞随机数字显示动画效果(附在线演示与demo源码下载)
- jquery心形点赞关注效果的简单实现
- Android贝塞尔动画实现QQ,虎牙等平台点赞效果初探
- android实现直播点赞飘心动画效果
- 一步一步实现Periscope点赞效果
- jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
- 心形点赞动画的实现
- android 飘心动画(直播点赞)效果(二)---贝塞尔曲线的实现
- jQuery点赞动画效果+1的代码实现
- 浅谈属性动画简单使用之实现爱的贝塞尔曲线浪漫告白效果(三)
- 一步一步教你实现Periscope点赞效果
- 浅谈属性动画简单使用之实现爱的贝塞尔曲线浪漫告白效果(三)
- jQuery实现的点赞随机数字显示动画效果(附在线演示与demo源码下载)
- 一步一步教你实现Periscope点赞效果