配色: 字号:
Android特效专辑(八)——实现心型起泡飞舞的特效,让你的APP瞬间暖心
2016-10-17 | 阅:  转:  |  分享 
  
Android特效专辑(八)——实现心型起泡飞舞的特效,让你的APP瞬间暖心

马上也要放年假了,家里估计会没网,更完这篇的话,可能要到年后了,不过在此期间会把更新内容都保存在本地,这样有网就可以发表了,也是极好的,今天说的这个特效,原本是Only上的一个小彩蛋的,我们来看看图片



只要我点击了Only这个字,下面就开始上升起起泡了,这个实现起来其实就是一个欲盖弥彰的动画而已,准备好三张颜色不一样的心型图片咯,这样的话,我们就开始动手来写一写吧!

首先新建一个工程——HeartFaom

准备工作就是准备图片咯

BezierEvaluator



单位转换以及计算轨迹

packagecom.lgl.heartfaom;



importandroid.animation.TypeEvaluator;

importandroid.graphics.PointF;



publicclassBezierEvaluatorimplementsTypeEvaluator{



privatePointFpointF1;

privatePointFpointF2;



publicBezierEvaluator(PointFpointF1,PointFpointF2){

this.pointF1=pointF1;

this.pointF2=pointF2;

}



@Override

publicPointFevaluate(floattime,PointFstartValue,PointFendValue){



floattimeLeft=1.0f-time;

PointFpoint=newPointF();//结果



point.x=timeLefttimeLefttimeLeft(startValue.x)+3

timeLefttimeLefttime(pointF1.x)+3timeLeft

timetime(pointF2.x)+timetimetime(endValue.x);



point.y=timeLefttimeLefttimeLeft(startValue.y)+3

timeLefttimeLefttime(pointF1.y)+3timeLeft

timetime(pointF2.y)+timetimetime(endValue.y);

returnpoint;

}

}



PeriscopeLayout



贝塞尔曲线的计算以及气泡的实现

packagecom.lgl.heartfaom;



importjava.util.Random;



importandroid.animation.Animator;

importandroid.animation.AnimatorListenerAdapter;

importandroid.animation.AnimatorSet;

importandroid.animation.ObjectAnimator;

importandroid.animation.ValueAnimator;

importandroid.annotation.TargetApi;

importandroid.content.Context;

importandroid.graphics.PointF;

importandroid.graphics.drawable.Drawable;

importandroid.os.Build;

importandroid.util.AttributeSet;

importandroid.view.View;

importandroid.view.animation.AccelerateDecelerateInterpolator;

importandroid.view.animation.AccelerateInterpolator;

importandroid.view.animation.DecelerateInterpolator;

importandroid.view.animation.Interpolator;

importandroid.view.animation.LinearInterpolator;

importandroid.widget.ImageView;

importandroid.widget.RelativeLayout;



publicclassPeriscopeLayoutextendsRelativeLayout{



privateInterpolatorline=newLinearInterpolator();//线性

privateInterpolatoracc=newAccelerateInterpolator();//加速

privateInterpolatordce=newDecelerateInterpolator();//减速

privateInterpolatoraccdec=newAccelerateDecelerateInterpolator();//先加速后减速

privateInterpolator[]interpolators;



privateintmHeight;

privateintmWidth;

privateLayoutParamslp;

privateDrawable[]drawables;

privateRandomrandom=newRandom();



privateintdHeight;

privateintdWidth;



publicPeriscopeLayout(Contextcontext){

super(context);

init();

}



publicPeriscopeLayout(Contextcontext,AttributeSetattrs){

super(context,attrs);

init();

}



publicPeriscopeLayout(Contextcontext,AttributeSetattrs,intdefStyleAttr){

super(context,attrs,defStyleAttr);

init();

}



@TargetApi(Build.VERSION_CODES.LOLLIPOP)

publicPeriscopeLayout(Contextcontext,AttributeSetattrs,

intdefStyleAttr,intdefStyleRes){

super(context,attrs,defStyleAttr,defStyleRes);

init();

}



privatevoidinit(){



//初始化显示的图片

drawables=newDrawable[3];

Drawablered=getResources().getDrawable(R.drawable.pl_red);

Drawableyellow=getResources().getDrawable(R.drawable.pl_yellow);

Drawableblue=getResources().getDrawable(R.drawable.pl_blue);



drawables[0]=red;

drawables[1]=yellow;

drawables[2]=blue;

//获取图的宽高用于后面的计算

//注意我这里3张图片的大小都是一样的,所以我只取了一个

dHeight=red.getIntrinsicHeight();

dWidth=red.getIntrinsicWidth();



//底部并且水平居中

lp=newLayoutParams(dWidth,dHeight);

lp.addRule(CENTER_HORIZONTAL,TRUE);//这里的TRUE要注意不是true

lp.addRule(ALIGN_PARENT_BOTTOM,TRUE);



//初始化插补器

interpolators=newInterpolator[4];

interpolators[0]=line;

interpolators[1]=acc;

interpolators[2]=dce;

interpolators[3]=accdec;



}



@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

mWidth=getMeasuredWidth();

mHeight=getMeasuredHeight();

}



publicvoidaddHeart(){



ImageViewimageView=newImageView(getContext());

//随机选一个

imageView.setImageDrawable(drawables[random.nextInt(3)]);

imageView.setLayoutParams(lp);



addView(imageView);



Animatorset=getAnimator(imageView);

set.addListener(newAnimEndListener(imageView));

set.start();



}



privateAnimatorgetAnimator(Viewtarget){

AnimatorSetset=getEnterAnimtor(target);



ValueAnimatorbezierValueAnimator=getBezierValueAnimator(target);



AnimatorSetfinalSet=newAnimatorSet();

finalSet.playSequentially(set);

finalSet.playSequentially(set,bezierValueAnimator);

finalSet.setInterpolator(interpolators[random.nextInt(4)]);

finalSet.setTarget(target);

returnfinalSet;

}



privateAnimatorSetgetEnterAnimtor(finalViewtarget){



ObjectAnimatoralpha=ObjectAnimator.ofFloat(target,View.ALPHA,0.2f,

1f);

ObjectAnimatorscaleX=ObjectAnimator.ofFloat(target,View.SCALE_X,

0.2f,1f);

ObjectAnimatorscaleY=ObjectAnimator.ofFloat(target,View.SCALE_Y,

0.2f,1f);

AnimatorSetenter=newAnimatorSet();

enter.setDuration(500);

enter.setInterpolator(newLinearInterpolator());

enter.playTogether(alpha,scaleX,scaleY);

enter.setTarget(target);

returnenter;

}



privateValueAnimatorgetBezierValueAnimator(Viewtarget){



//初始化一个贝塞尔计算器--传入

BezierEvaluatorevaluator=newBezierEvaluator(getPointF(2),

getPointF(1));



//这里最好画个图理解一下传入了起点和终点

ValueAnimatoranimator=ValueAnimator.ofObject(evaluator,newPointF(

(mWidth-dWidth)/2,mHeight-dHeight),

newPointF(random.nextInt(getWidth()),0));

animator.addUpdateListener(newBezierListenr(target));

animator.setTarget(target);

animator.setDuration(3000);

returnanimator;

}



/

获取中间的两个点



@paramscale

/

privatePointFgetPointF(intscale){



PointFpointF=newPointF();

pointF.x=random.nextInt((mWidth-100));//减去100是为了控制x轴活动范围,看效果随意~~

//再Y轴上为了确保第二个点在第一个点之上,我把Y分成了上下两半这样动画效果好一些也可以用其他方法

pointF.y=random.nextInt((mHeight-100))/scale;

returnpoinwww.shanxiwang.nettF;

}



privateclassBezierListenrimplementsValueAnimator.AnimatorUpdateListener{



privateViewtarget;



publicBezierListenr(Viewtarget){

this.target=target;

}



@Override

publicvoidonAnimationUpdate(ValueAnimatoranimation){

//这里获取到贝塞尔曲线计算出来的的xy值赋值给view这样就能让爱心随着曲线走啦

PointFpointF=(PointF)animation.getAnimatedValue();

target.setX(pointF.x);

target.setY(pointF.y);

//这里顺便做一个alpha动画

target.setAlpha(1-animation.getAnimatedFraction());

}

}



privateclassAnimEndListenerextendsAnimatorListenerAdapter{

privateViewtarget;



publicAnimEndListener(Viewtarget){

this.target=target;

}



@Override

publicvoidonAnimationEnd(Animatoranimation){

super.onAnimationEnd(animation);

//因为不停的add导致子view数量只增不减,所以在view动画结束后remove掉

removeView((target));

}

}

}



activity_main.xml



布局的实现


xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#000">




android:id="@+id/btn_start"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:text="飞舞吧!"/>




android:id="@+id/periscope"

android:layout_width="match_parent"

android:layout_height="match_parent">









MainActivity



接着就是怎么去使用它了

packagecom.lgl.heartfaom;



importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.view.View;

importandroid.view.View.OnClickListener;

importandroid.widget.Button;



publicclassMainActivityextendsActivity{



privateButtonbtn_start;

//心型气泡

privatePeriscopeLayoutperiscopeLayout;



@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//初始化

periscopeLayout=(PeriscopeLayout)findViewById(R.id.periscope);



btn_start=(Button)findViewById(R.id.btn_start);

btn_start.setOnClickListener(newOnClickListener(){



@Override

publicvoidonClick(Viewv){

//调用添加泡泡的方法

periscopeLayout.addHeart();

}

});

}

}



好,我们接下来就可以运行一下试试实际上的效果了



觉得不错的点个赞哦!

献花(0)
+1
(本文系网络学习天...首藏)