Android 擴散效果切換頁面

最近發現挺多應用使用了這種效果(比如愛奇藝的tv投屏按鈕):

擴散效果圖

核心就是通過 PorterDuffXfermode (隨便一搜就有好多好文章介紹)實現,看明白了這個圖片混合原理就相當簡單了。

我是自定義了一個SpreadView:

public class SpreadView extends View {

    private Context context;
    private Bitmap maskBitmap;
    private Paint paint;
    private PorterDuffXfermode porterDuffXfermode;
    private Paint edgePaint;
    private float progress;
    private float cx, cy;
    private int length;

    public SpreadView(Context context, Bitmap bitmap) {
        super(context);
        init(context);
        /*
        * maskView 需要 measure 之後才能使用 maskView.draw(canvas)
        * */
        this.maskBitmap = bitmap;
    }

    private void init(Context context) {
        this.context = context;
        edgePaint = new Paint();
        edgePaint.setColor(Color.WHITE);
        edgePaint.setStyle(Paint.Style.STROKE);
        edgePaint.setStrokeWidth(0);
        edgePaint.setAlpha(100);

        paint = new Paint();
        paint.setAntiAlias(true);
        porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    private void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }

    public void startAnim(float cx, float cy, int length) {
        this.cx = cx;
        this.cy = cy;
        this.length = length;
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "progress", 0, 1);
        objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (animatorListener != null) {
                    animatorListener.animFinished();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        objectAnimator.setDuration(3000);
        objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        objectAnimator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);
        canvas.drawBitmap(getBitmapCircle(), 0, 0, paint);
        paint.setXfermode(porterDuffXfermode);
        canvas.drawBitmap(maskBitmap, 0, 0, paint);
        paint.setXfermode(null);

        float edgeLength = 300;
        edgePaint.setStrokeWidth(100 + edgeLength * progress);
        canvas.drawCircle(cx, cy, length * progress + 50 + edgeLength * progress / 2, edgePaint);
    }

    private Bitmap getBitmapCircle() {
        Bitmap bitmap = Bitmap.createBitmap(maskBitmap.getWidth(), maskBitmap.getHeight(), Bitmap.Config.ALPHA_8);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        canvas.drawCircle(cx, cy, length * progress, paint);
        return bitmap;
    }

    private AnimatorListener animatorListener;

    public void setAnimatorListener(AnimatorListener animatorListener) {
        this.animatorListener = animatorListener;
    }

    public interface AnimatorListener {
        void animFinished();
    }
}

第一頁和第二頁佈局除了背景顏色不同,右上角是一個相同的按鈕:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.test.demoone.spread_anim.SpreadAnimActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="第一頁"
        android:textColor="@color/colorWhite"
        android:textSize="30sp" />

    <TextView
        android:id="@+id/testClick"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp"
        android:background="#00ff00"
        android:paddingBottom="12dp"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:paddingTop="12dp"
        android:text="切換" />

</RelativeLayout>

Activity種的點擊事件這樣處理:

public class SpreadAnimActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView buttonClick;
    private RelativeLayout rootView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_spread_anim);
        rootView = findViewById(R.id.rootView);
        buttonClick = findViewById(R.id.testClick);
        buttonClick.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.testClick:
                int activityWidth = rootView.getMeasuredWidth();
                int activityHeight = rootView.getMeasuredHeight();
                View secondActivityView = LayoutInflater.from(this).inflate(R.layout.activity_second, rootView, false);
                secondActivityView.measure(View.MeasureSpec.makeMeasureSpec(activityWidth, View.MeasureSpec.EXACTLY),
                        View.MeasureSpec.makeMeasureSpec(activityHeight, View.MeasureSpec.EXACTLY));
                secondActivityView.layout(0, 0, activityWidth, activityHeight);
                final SpreadView spreadView = new SpreadView(this, getBitmapFromView(secondActivityView));
                //爲了不造成連續點擊
                spreadView.setFocusable(true);
                spreadView.setFocusableInTouchMode(true);
                spreadView.setClickable(true);
                rootView.addView(spreadView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

                float cx = buttonClick.getX() + buttonClick.getMeasuredWidth() / 2;
                float cy = buttonClick.getY() + buttonClick.getMeasuredHeight() / 2;
                spreadView.startAnim(cx, cy, (int) Math.sqrt(Math.pow(cx, 2) + Math.pow(activityHeight - cy, 2)));

                spreadView.setAnimatorListener(new SpreadView.AnimatorListener() {
                    @Override
                    public void animFinished() {
                        Intent intent = new Intent(SpreadAnimActivity.this, SecondActivity.class);
                        startActivity(intent);
                        finish();
                        overridePendingTransition(0, 0);
                    }
                });
                break;
        }
    }

    private Bitmap getBitmapFromView(View view) {
        Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(),
                view.getMeasuredHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        view.draw(canvas);

        return bitmap;
    }
}

好了... 在家繼續隔離... 加油💪

發佈了24 篇原創文章 · 獲贊 14 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章