最近發現挺多應用使用了這種效果(比如愛奇藝的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;
}
}
好了... 在家繼續隔離... 加油💪