Android特效专辑(八)——实现心型起泡飞舞的特效,让你的APP瞬间暖心

    xiaoxiao2021-12-15  47

    标签: androidapp图片动画   4596人阅读  评论(12)  收藏  举报   分类: Android(110) 

    目录(?)[+]

    Android特效专辑(八)——实现心型起泡飞舞的特效,让你的APP瞬间暖心


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

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

    BezierEvaluator

    单位转换以及计算轨迹 package com.lgl.heartfaom; import android.animation.TypeEvaluator; import android.graphics.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; } @Override public PointF evaluate(float time, PointF startValue, PointF endValue) { float timeLeft = 1.0f - time; PointF point = new PointF();// 结果 point.x = timeLeft * timeLeft * timeLeft * (startValue.x) + 3 * timeLeft * timeLeft * time * (pointF1.x) + 3 * timeLeft * time * time * (pointF2.x) + time * time * time * (endValue.x); point.y = timeLeft * timeLeft * timeLeft * (startValue.y) + 3 * timeLeft * timeLeft * time * (pointF1.y) + 3 * timeLeft * time * time * (pointF2.y) + time * time * time * (endValue.y); return point; } } 1234567891011121314151617181920212223242526272829303132 1234567891011121314151617181920212223242526272829303132

    PeriscopeLayout

    贝塞尔曲线的计算以及气泡的实现 package com.lgl.heartfaom; 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.annotation.TargetApi; import android.content.Context; import android.graphics.PointF; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.widget.ImageView; import android.widget.RelativeLayout; public class PeriscopeLayout extends RelativeLayout { private Interpolator line = new LinearInterpolator();// 线性 private Interpolator acc = new AccelerateInterpolator();// 加速 private Interpolator dce = new DecelerateInterpolator();// 减速 private Interpolator accdec = new AccelerateDecelerateInterpolator();// 先加速后减速 private Interpolator[] interpolators; private int mHeight; private int mWidth; private LayoutParams lp; private Drawable[] drawables; private Random random = new Random(); private int dHeight; private int dWidth; public PeriscopeLayout(Context context) { super(context); init(); } public PeriscopeLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public PeriscopeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public PeriscopeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { // 初始化显示的图片 drawables = new Drawable[3]; Drawable red = getResources().getDrawable(R.drawable.pl_red); Drawable yellow = getResources().getDrawable(R.drawable.pl_yellow); Drawable blue = getResources().getDrawable(R.drawable.pl_blue); drawables[0] = red; drawables[1] = yellow; drawables[2] = blue; // 获取图的宽高 用于后面的计算 // 注意 我这里3张图片的大小都是一样的,所以我只取了一个 dHeight = red.getIntrinsicHeight(); dWidth = red.getIntrinsicWidth(); // 底部 并且 水平居中 lp = new LayoutParams(dWidth, dHeight); lp.addRule(CENTER_HORIZONTAL, TRUE);// 这里的TRUE 要注意 不是true lp.addRule(ALIGN_PARENT_BOTTOM, TRUE); // 初始化插补器 interpolators = new Interpolator[4]; interpolators[0] = line; interpolators[1] = acc; interpolators[2] = dce; interpolators[3] = accdec; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = getMeasuredWidth(); mHeight = getMeasuredHeight(); } public void addHeart() { ImageView imageView = new ImageView(getContext()); // 随机选一个 imageView.setImageDrawable(drawables[random.nextInt(3)]); imageView.setLayoutParams(lp); addView(imageView); Animator set = getAnimator(imageView); set.addListener(new AnimEndListener(imageView)); set.start(); } private Animator getAnimator(View target) { AnimatorSet set = getEnterAnimtor(target); ValueAnimator bezierValueAnimator = getBezierValueAnimator(target); AnimatorSet finalSet = new AnimatorSet(); finalSet.playSequentially(set); finalSet.playSequentially(set, bezierValueAnimator); finalSet.setInterpolator(interpolators[random.nextInt(4)]); finalSet.setTarget(target); return finalSet; } private AnimatorSet getEnterAnimtor(final View target) { ObjectAnimator alpha = ObjectAnimator.ofFloat(target, View.ALPHA, 0.2f, 1f); ObjectAnimator scaleX = ObjectAnimator.ofFloat(target, View.SCALE_X, 0.2f, 1f); ObjectAnimator scaleY = ObjectAnimator.ofFloat(target, View.SCALE_Y, 0.2f, 1f); AnimatorSet enter = new AnimatorSet(); enter.setDuration(500); enter.setInterpolator(new LinearInterpolator()); enter.playTogether(alpha, scaleX, scaleY); enter.setTarget(target); return enter; } private ValueAnimator getBezierValueAnimator(View target) { // 初始化一个贝塞尔计算器- - 传入 BezierEvaluator evaluator = new BezierEvaluator(getPointF(2), getPointF(1)); // 这里最好画个图 理解一下 传入了起点 和 终点 ValueAnimator animator = ValueAnimator.ofObject(evaluator, new PointF( (mWidth - dWidth) / 2, mHeight - dHeight), new PointF(random.nextInt(getWidth()), 0)); animator.addUpdateListener(new BezierListenr(target)); animator.setTarget(target); animator.setDuration(3000); return animator; } /** * 获取中间的两个 点 * * @param scale */ private PointF getPointF(int scale) { PointF pointF = new PointF(); pointF.x = random.nextInt((mWidth - 100));// 减去100 是为了控制 x轴活动范围,看效果 随意~~ // 再Y轴上 为了确保第二个点 在第一个点之上,我把Y分成了上下两半 这样动画效果好一些 也可以用其他方法 pointF.y = random.nextInt((mHeight - 100)) / scale; return pointF; } private class BezierListenr implements ValueAnimator.AnimatorUpdateListener { private View target; public BezierListenr(View target) { this.target = target; } @Override public void onAnimationUpdate(ValueAnimator animation) { // 这里获取到贝塞尔曲线计算出来的的x y值 赋值给view 这样就能让爱心随着曲线走啦 PointF pointF = (PointF) animation.getAnimatedValue(); target.setX(pointF.x); target.setY(pointF.y); // 这里顺便做一个alpha动画 target.setAlpha(1 - animation.getAnimatedFraction()); } } private class AnimEndListener extends AnimatorListenerAdapter { private View target; public AnimEndListener(View target) { this.target = target; } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); // 因为不停的add 导致子view数量只增不减,所以在view动画结束后remove掉 removeView((target)); } } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209

    activity_main.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:background="#000" > <Button android:id="@+id/btn_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="飞舞吧!" /> <com.lgl.heartfaom.PeriscopeLayout android:id="@+id/periscope" android:layout_width="match_parent" android:layout_height="match_parent" > </com.lgl.heartfaom.PeriscopeLayout> </RelativeLayout> 1234567891011121314151617181920 1234567891011121314151617181920

    MainActivity

    接着就是怎么去使用它了 package com.lgl.heartfaom; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button btn_start; // 心型气泡 private PeriscopeLayout periscopeLayout; @Override protected void onCreate(Bundle savedInstanceState) { 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(new OnClickListener() { @Override public void onClick(View v) { // 调用添加泡泡的方法 periscopeLayout.addHeart(); } }); } } 123456789101112131415161718192021222324252627282930313233 123456789101112131415161718192021222324252627282930313233

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

    觉得不错的点个赞哦!

    Demo下载地址:http://download.csdn.net/detail/qq_26787115/9422603

    转载请注明原文地址: https://ju.6miu.com/read-1000038.html

    最新回复(0)