Jelajahi Sumber

烟花特效

LAPTOP-K69FCNBP\crius 2 tahun lalu
induk
melakukan
f03d57e54d

+ 1 - 0
.idea/misc.xml

@@ -19,6 +19,7 @@
         <entry key="..\:/Progect/gitee/EffectDemo/app/src/main/res/layout/activity_umeng_login.xml" value="0.18" />
         <entry key="..\:/Progect/gitee/EffectDemo/app/src/main/res/layout/activity_view.xml" value="0.25" />
         <entry key="..\:/Progect/gitee/EffectDemo/app/src/main/res/layout/activity_web.xml" value="0.1816123188405797" />
+        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/layout/activity_congratulations.xml" value="0.15274949083503056" />
       </map>
     </option>
   </component>

+ 3 - 0
app/src/main/java/com/xunao/effectdemo/activity/CongratulationsActivity.kt

@@ -23,6 +23,9 @@ class CongratulationsActivity : Activity() {
         btn_start.setOnClickListener{v->
             lottie_view.playAnimation()
         }
+        fl_firework.setOnClickListener { v ->
+            fl_firework.like()
+        }
 
         like.setDotNum(4,colorInt)
     }

+ 254 - 0
app/src/main/java/com/xunao/effectdemo/view/FireworkView.java

@@ -0,0 +1,254 @@
+package com.xunao.effectdemo.view;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+
+import androidx.annotation.Nullable;
+
+
+/**
+ * Created
+ * by jaren on 2017/5/26.
+ */
+
+public class FireworkView extends View{
+
+    /**
+     * 圆最大半径(心形)
+     */
+    private float mRadius;
+    /**
+     * View变化用时
+     */
+    private int mCycleTime;
+    /**
+     * Bézier曲线画圆的近似常数
+     */
+    private static final float c = 0.551915024494f;
+    /**
+     * 环绕圆点的颜色
+     */
+    private static final int[] dotColors = {0xffdaa9fa, 0xfff2bf4b, 0xffe3bca6, 0xff329aed,
+            0xffb1eb99, 0xff67c9ad, 0xffde6bac};
+    /**
+     * 4.圆环减消失、心形放大、周围环绕十四圆点
+     */
+    private static final int RING_DOT__HEART_VIEW = 3;
+    /**
+     * 5.环绕的十四圆点向外移动并缩小、透明度渐变、渐隐
+     */
+    private static final int DOT__HEART_VIEW = 4;
+
+    private float mCenterX;
+    private float mCenterY;
+    private Paint mPaint;
+    private ValueAnimator animatorTime;
+    private int mCurrentRadius;
+    private int mCurrentState;
+    private float mCurrentPercent;
+
+    private float rDotL;
+    private float offL;
+    private boolean isMax;
+    private float dotR;
+
+
+    public FireworkView(Context context) {
+        this(context, null);
+    }
+
+    public FireworkView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FireworkView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mRadius = dp2px(20);
+        mCycleTime = 600;
+        mCenterX = mRadius;
+        mCenterY = mRadius;
+        mPaint = new Paint();
+        mCurrentRadius = (int) mRadius;
+        dotR = mRadius / 6;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        canvas.translate(mCenterX, mCenterY);//使坐标原点在canvas中心位置
+        switch (mCurrentState) {
+            case RING_DOT__HEART_VIEW:
+                drawDotWithRing(canvas, mCurrentRadius);
+                break;
+            case DOT__HEART_VIEW:
+                drawDot(canvas);
+                break;
+        }
+    }
+
+    //绘制圆点、圆环、心形
+    private void drawDotWithRing(Canvas canvas, int radius) {
+        mPaint.setAntiAlias(true);
+
+        mPaint.setStyle(Paint.Style.STROKE);
+        mCurrentPercent = (1f - mCurrentPercent > 1f ? 1f : 1f - mCurrentPercent) * 1f;
+        //用于计算圆环宽度,最小0,与动画进度负相关
+//        mPaint.setStrokeWidth(2 * mRadius * mCurrentPercent);
+
+        float innerR = radius - mRadius * mCurrentPercent + dotR;
+        double angleB = -Math.PI / 20;
+
+        offL += dotR / 14;
+        rDotL = innerR + offL;
+
+        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+        for (int i = 0; i < 14; i++) {
+            mPaint.setColor(dotColors[i % 7]);
+            float cx = (float) (rDotL * Math.sin(angleB));
+            float cy = (float) (rDotL * Math.cos(angleB));
+            if(i % 3 == 0){
+                mPaint.setStrokeWidth(dotR);
+                canvas.drawCircle(cx, cy, dotR, mPaint);
+            }else if(i % 3 == 1){
+                mPaint.setStrokeWidth(dotR);
+                canvas.drawText("/", cx, cy, mPaint);
+            }else{
+                mPaint.setStrokeWidth(dotR);
+                canvas.drawRect(cx - 1, cy - 1, cx + 1, cy + 1, mPaint);
+            }
+
+            angleB += 2 * Math.PI / 14;
+        }
+        mCurrentRadius = (int) (mRadius / 3 + offL * 4);
+
+    }
+
+    //绘制圆点、心形
+    private void drawDot(Canvas canvas) {
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.FILL);
+
+        double angleB = -Math.PI / 20;
+        float dotRL;
+        if (rDotL < 2.6 * mRadius) {//限制圆点的扩散范围
+            rDotL += dotR / 14;
+        }
+        if (!isMax && mCurrentRadius <= 1.1 * mRadius) {
+            offL += dotR / 14;
+            mCurrentRadius = (int) (mRadius / 3 + offL * 4);
+
+        } else {
+            isMax = true;
+        }
+
+        dotRL = (dotR * (1 - mCurrentPercent) * 4) > dotR ? dotR :
+                (dotR * (1 - mCurrentPercent) * 3);
+        mPaint.setAlpha((int) (255 * (1 - mCurrentPercent)));//圆点逐渐透明
+        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+        for (int i = 0; i < 14; i++) {
+            mPaint.setColor(dotColors[i % 7]);
+            float cx = (float) (rDotL * Math.sin(angleB));
+            float cy = (float) (rDotL * Math.cos(angleB));
+            if(i % 3 == 0){
+                mPaint.setStrokeWidth(dotRL);
+                canvas.drawCircle(cx, cy, dotRL, mPaint);
+            }else if(i % 3 == 1){
+                mPaint.setStrokeWidth(dotRL);
+                canvas.drawText("/", cx, cy, mPaint);
+            }else{
+                mPaint.setStrokeWidth(dotRL);
+                canvas.drawRect(cx - 1, cy - 1, cx + 1, cy + 1, mPaint);
+            }
+
+            angleB += 2 * Math.PI / 14;
+        }
+
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mCenterX = w / 2;
+        mCenterY = h / 2;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int mWidth, mHeight;
+        mWidth = (int) (5.2 * mRadius + 2 * dotR);
+        mHeight = (int) (5.2 * mRadius + 2 * dotR);
+        setMeasuredDimension(mWidth, mHeight);
+
+    }
+
+    /**
+     * 点赞的变化效果
+     */
+    public void like() {
+        if (animatorTime != null && animatorTime.isRunning()) {
+            return;
+        }
+        resetState();
+        animatorTime = ValueAnimator.ofInt(0, 1200);
+        animatorTime.setDuration(mCycleTime);
+        animatorTime.setInterpolator(new DecelerateInterpolator());//需要随时间匀速变化
+        animatorTime.start();
+        animatorTime.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                int animatedValue = (int) animation.getAnimatedValue();
+
+                    if (animatedValue <= 480) {
+                    float percent = calcPercent(1f, 480f, animatedValue);//内环半径增大直至消亡
+                    mCurrentPercent = percent;
+                    mCurrentRadius = (int) (2 * mRadius);//外环半径不再改变
+                    mCurrentState = RING_DOT__HEART_VIEW;
+                    invalidate();
+                }
+                  else if (animatedValue <= 1200) {
+                    float percent = calcPercent(480f, 1200f, animatedValue);
+                    mCurrentPercent = percent;
+                    mCurrentState = DOT__HEART_VIEW;
+                    invalidate();
+                }
+            }
+        });
+
+    }
+
+    /**
+     * 重置为初始状态
+     */
+    private void resetState() {
+        mCurrentPercent = 0;
+        mCurrentRadius = 0;
+        isMax = false;
+        rDotL = 0;
+        offL = 0;
+    }
+
+    private float calcPercent(float start, float end, float current) {
+        return (current - start) / (end - start);
+    }
+
+    private float dp2px(int value) {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value,
+                getResources().getDisplayMetrics());
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (animatorTime != null) {
+            animatorTime.removeAllListeners();
+        }
+    }
+}

+ 15 - 0
app/src/main/res/layout/activity_congratulations.xml

@@ -30,6 +30,21 @@
                android:layout_width="50dp"
                android:layout_height="50dp"/>
        </RelativeLayout>
+       <FrameLayout
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:layout_gravity="center">
+           <com.xunao.effectdemo.view.FireworkView
+               android:id="@+id/fl_firework"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content" />
+           <TextView
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="center"
+               android:text="烟花"
+               android:textColor="#657487"/>
+       </FrameLayout>
        <com.airbnb.lottie.LottieAnimationView
            android:layout_width="200dp"
            android:layout_height="200dp"