优秀案例自定义控件

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));
    }
}
上一篇下一篇

猜你喜欢

热点阅读