Android蒙层特定区域透明的实现
2020-05-14 本文已影响0人
lion_6bb6
刚好最近在做蒙层指引,记录下来,方便后续使用。
先上一张效果图:
screen.png
具体代码实现:
1、自定义drawable
package com.xsoft.demo;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class CoverDrawable extends Drawable {
private Drawable drawable;
private Paint paint;
private Path path = new Path();
public CoverDrawable(@NonNull Drawable drawable) {
this.drawable = drawable;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(0xffffffff);
}
/**
* 绘制圆
*
* @param drawable
* @param x
* @param y
* @param radius
*/
public CoverDrawable(@NonNull Drawable drawable,
int x, int y, int radius) {
this(drawable);
path.addCircle(x, y, radius, Path.Direction.CW);
}
/**
* 绘制圆角矩形
*
* @param drawable
* @param left
* @param top
* @param right
* @param bottom
* @param rx
* @param ry
*/
public CoverDrawable(@NonNull Drawable drawable,
int left, int top, int right, int bottom, int rx, int ry) {
this(drawable);
path.addRoundRect(left, top, right, bottom, rx, ry, Path.Direction.CW);
}
@Override
public void draw(@NonNull Canvas canvas) {
drawable.setBounds(getBounds());
if (path == null || path.isEmpty()) {
drawable.draw(canvas);
} else {
//将绘制操作保存在新的图层,因为图像合成是很昂贵的操作,将用到硬件加速,这里将图像合成的处理放到离屏缓存中进行
int saveCount = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), paint, Canvas.ALL_SAVE_FLAG);
//绘制目标图
drawable.draw(canvas);
//设置混合模式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//绘制原图
canvas.drawPath(path, paint);
//清除混合模式
paint.setXfermode(null);
//还原画布
canvas.restoreToCount(saveCount);
}
}
@Override
public void setAlpha(int i) {
drawable.setAlpha(i);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
drawable.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return drawable.getOpacity();
}
}
如果需要实现其他的效果,只需增加构造方法,修改path即可。
可以看出最核心的技术就是使用混合模式PorterDuffXfermode,这个博客讲解的比较透彻。
2、布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/fl1"
android:layout_width="match_parent"
android:layout_height="200dp">
</FrameLayout>
<FrameLayout
android:id="@+id/fl2"
android:layout_width="match_parent"
android:layout_height="200dp">
</FrameLayout>
</LinearLayout>
3、activity实现
package com.xsoft.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.fl1).setBackground(new CoverDrawable(new ColorDrawable(0xb2000000),
100, 100, 50));
findViewById(R.id.fl2).setBackground(new CoverDrawable(new ColorDrawable(0xb2000000),
50, 10, 300, 150, 8, 8));
}
}