糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 贝萨尔曲线实现Periscope心形点赞动画效果

贝萨尔曲线实现Periscope心形点赞动画效果

时间:2021-05-01 13:32:24

相关推荐

贝萨尔曲线实现Periscope心形点赞动画效果

先来个效果图

这个动画效果主要几个关注点是:

一、自定义的RelativeLayout中动态加载ImageView

二、刚开始的三个还没移动的动画效果anpha和scaleX,scaleY ,用ObjectAnimator加载

三、红心移动效果,运用了ValueAnimator的TypeEvalutors(估值器) 和addUpdateListener监听,在TypeEvalutors获取了贝塞尔曲线运动时所随机移动的每一个PointF,

然后在监听中获取这个PointF,赋值给imageView的对象,这样就实现了imageView的对象不的x,y坐标不停的改变,实现移动效果

四、最后,在动画结束后remove(imageView)移除对象

详细代码:

先来个layout的xml

[java]view plaincopyprint?<RelativeLayoutxmlns:android=“/apk/res/android”xmlns:tools=”/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.MyLayoutandroid: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="/apk/res/android"xmlns:tools="/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.MyLayoutandroid: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 plaincopyprint?packagecom.example.test_periscopedemo;importandroid.os.Bundle;importandroid.app.Activity;importandroid.view.Menu;importandroid.view.View;publicclassMainActivityextendsActivity{MyLayoutmyLayout;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myLayout=(MyLayout)findViewById(R.id.myLayout);}publicvoidstartClick(Viewview){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,这个主要的实现类

[java]view plaincopyprint?packagecom.example.test_periscopedemo;importjava.util.Random;importandroid.animation.Animator;importandroid.animation.AnimatorListenerAdapter;importandroid.animation.AnimatorSet;importandroid.animation.ObjectAnimator;importandroid.animation.ValueAnimator;importandroid.animation.ValueAnimator.AnimatorUpdateListener;importandroid.content.Context;importandroid.graphics.BitmapFactory;importandroid.graphics.PointF;importandroid.graphics.drawable.Drawable;importandroid.util.AttributeSet;importandroid.view.View;importandroid.view.animation.AnimationSet;importandroid.widget.ImageView;importandroid.widget.RelativeLayout;publicclassMyLayoutextendsRelativeLayout{Randomrandom;Drawableblue,red,yellow;LayoutParamslp;intdWidth,dHeight;intmWidth,mHeight;Drawable[]drawables=newDrawable[3];publicMyLayout(Contextcontext,AttributeSetattrs){super(context,attrs);init();}@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){super.onMeasure(widthMeasureSpec,heightMeasureSpec);mWidth=getMeasuredWidth();mHeight=getMeasuredHeight();}privatevoidinit(){dWidth=BitmapFactory.decodeResource(getResources(),R.drawable.pl_blue).getWidth();dHeight=BitmapFactory.decodeResource(getResources(),R.drawable.pl_blue).getHeight();random=newRandom();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=newLayoutParams(dWidth,dHeight);lp.addRule(CENTER_HORIZONTAL,TRUE);//这里的TRUE要注意不是truelp.addRule(ALIGN_PARENT_BOTTOM,TRUE);}publicvoidaddLayout(){ImageViewiv=newImageView(getContext());iv.setLayoutParams(lp);addView(iv);iv.setImageDrawable(drawables[random.nextInt(3)]);getAnimator(iv);}privatevoidgetAnimator(finalViewiv){ValueAnimatorva=ValueAnimator.ofObject(newBezierEvaluator(newPointF(mWidth/2-dWidth/2,mHeight-dHeight),getPointF()),newPointF((mWidth-dWidth)/2,mHeight-dHeight),newPointF(random.nextInt(getWidth()),0));//随机va.addUpdateListener(newAnimatorUpdateListener(){@OverridepublicvoidonAnimationUpdate(ValueAnimatoranimation){PointFpointF=(PointF)animation.getAnimatedValue();iv.setX(pointF.x);iv.setY(pointF.y);//这里偷个懒,顺便做一个alpha动画,这样alpha渐变也完成啦iv.setAlpha(1-animation.getAnimatedFraction());}});ObjectAnimatoralpha=ObjectAnimator.ofFloat(iv,”alpha”,0.2f,1.0f);ObjectAnimatorscaleX=ObjectAnimator.ofFloat(iv,”scaleX”,0.2f,1.0f);ObjectAnimatorscaleY=ObjectAnimator.ofFloat(iv,”scaleY”,0.2f,1.0f);AnimatorSetset=newAnimatorSet();set.setDuration(3000);set.playTogether(alpha,scaleX,scaleY);set.play(va).after(alpha);set.setTarget(iv);set.addListener(newAnimatorListenerAdapter(){@OverridepublicvoidonAnimationEnd(Animatoranimation){super.onAnimationEnd(animation);System.out.println(”结束”);removeView(iv);}});set.start();}privatePointFgetPointF(){PointFp=newPointF();p.x=random.nextInt(mWidth);p.y=50;returnp;}}

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计算出的因子计算出当前时间的属性值,即在动画执行的不同的时间,返回不同的值,就在这利用贝塞尔曲线工式,获取一个随机移动的点的坐标做为返回值

[java]view plaincopyprint?packagecom.example.test_periscopedemo;importandroid.animation.TypeEvaluator;importandroid.graphics.PointF;//我们自定义一个BezierEvaluator实现TypeEvaluator//由于我们view的移动需要控制xy所以就传入PointF作为参数,是不是感觉完全契合??publicclassBezierEvaluatorimplementsTypeEvaluator<PointF>{privatePointFpointF1;//途径的两个点privatePointFpointF2;publicBezierEvaluator(PointFpointF1,PointFpointF2){this.pointF1=pointF1;this.pointF2=pointF2;System.out.println(”p1=”+pointF1);System.out.println(”p2=”+pointF2);}@OverridepublicPointFevaluate(floattime,PointFstartValue,PointFendValue){floattimeLeft=1.0f-time;PointFpoint=newPointF();//结果PointFpoint0=(PointF)startValue;//起点PointFpoint3=(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);returnpoint;}}

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心形点赞动画效果》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。