IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android两种水印的添加方法(底层显示,顶层覆盖) -> 正文阅读

[移动开发]android两种水印的添加方法(底层显示,顶层覆盖)

好多办公软件需要添加水印,添加水印一般有两种,一种是在布局中设置显示在底层,不会遮挡上层内容,实现比较繁琐;另一种是覆盖在最上层,会有遮挡的问题,实现较简单

方法一:先实现简单覆盖在上面的

/**
 * 水印
 * 大概思路是,首先获取当前页面的底层布局,然后在布局最上层添加一个全屏的带有水印的FrameLayout布局。
 * 自定义一个Drawable,把它当作水印,然后设置到FrameLayout布局的背景。
 */
public class WatermarkUtil {
    /**
     * 水印文本
     */
    private String mText;
    /**
     * 字体颜色,十六进制形式,例如:0xAEAEAEAE
     */
    private int mTextColor;
    /**
     * 字体大小,单位为sp
     */
    private float mTextSize;
    /**
     * 旋转角度
     */
    private float mRotation;
    private static WatermarkUtil sInstance;

    private WatermarkUtil() {
        mText = "";
        mTextColor = 0xAEAEAEAE;
        mTextSize = 18;
        mRotation = -25;
    }

    public static WatermarkUtil getInstance() {
        if (sInstance == null) {
            synchronized (WatermarkUtil.class) {
                sInstance = new WatermarkUtil();
            }
        }
        return sInstance;
    }

    /**
     * 设置水印文本
     *
     * @param text 文本
     * @return Watermark实例
     */
    public WatermarkUtil setText(String text) {
        mText = text;
        return sInstance;
    }

    /**
     * 设置字体颜色
     *
     * @param color 颜色,十六进制形式,例如:0xAEAEAEAE
     * @return Watermark实例
     */
    public WatermarkUtil setTextColor(int color) {
        mTextColor = color;
        return sInstance;
    }

    /**
     * 设置字体大小
     *
     * @param size 大小,单位为sp
     * @return Watermark实例
     */
    public WatermarkUtil setTextSize(float size) {
        mTextSize = size;
        return sInstance;
    }

    /**
     * 设置旋转角度
     *
     * @param degrees 度数
     * @return Watermark实例
     */
    public WatermarkUtil setRotation(float degrees) {
        mRotation = degrees;
        return sInstance;
    }

    /**
     * 显示水印,铺满整个页面
     *
     * @param activity 活动
     */
    public void show(Activity activity) {
        show(activity, mText);
    }

    /**
     * 显示水印,铺满整个页面
     *
     * @param activity 活动
     * @param text     水印
     */
    public void show(Activity activity, String text) {
        WatermarkDrawable drawable = new WatermarkDrawable();
        drawable.mText = text;
        drawable.mTextColor = mTextColor;
        drawable.mTextSize = mTextSize;
        drawable.mRotation = mRotation;

        ViewGroup rootView = activity.findViewById(android.R.id.content);
        FrameLayout layout = new FrameLayout(activity);
        layout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));

        layout.setBackground(drawable);
        rootView.addView(layout);
    }

    /**
     * 显示水印,铺满整个页面
     *
     * @param viewGroup 活动
     */
    public void show(ViewGroup viewGroup) {
        show(viewGroup, mText);
    }

    /**
     * 显示水印,铺满整个页面
     *
     * @param viewGroup 活动
     * @param text     水印
     */
    public void show(ViewGroup viewGroup, String text) {
        try{
            WatermarkDrawable drawable = new WatermarkDrawable();
            drawable.mText = text;
            drawable.mTextColor = mTextColor;
            drawable.mTextSize = mTextSize;
            drawable.mRotation = mRotation;

//        ViewGroup rootView = activity.findViewById(android.R.id.content);
            FrameLayout layout = new FrameLayout(viewGroup.getContext());
            layout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT));

            layout.setBackground(drawable);
            viewGroup.addView(layout);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private class WatermarkDrawable extends Drawable {
        private Paint mPaint;
        /**
         * 水印文本
         */
        private String mText;
        /**
         * 字体颜色,十六进制形式,例如:0xAEAEAEAE
         */
        private int mTextColor;
        /**
         * 字体大小,单位为sp
         */
        private float mTextSize;
        /**
         * 旋转角度
         */
        private float mRotation;

        private WatermarkDrawable() {
            mPaint = new Paint();
        }

        @Override
        public void draw(Canvas canvas) {
            int width = getBounds().right;
            int height = getBounds().bottom;
            int diagonal = (int) Math.sqrt(width * width + height * height); // 对角线的长度

            mPaint.setColor(mTextColor);
            mPaint.setTextSize(DrawUtil.sp2px(mTextSize)); // DrawUtil.sp2px这个方法是将sp转换成px
            mPaint.setAntiAlias(true);
            float textWidth = mPaint.measureText(mText);
            //设置不从原点开始绘制,以免遮挡导航栏
            canvas.translate(0, 150);
            canvas.drawColor(0x00000000);
            canvas.rotate(mRotation);
            int index = 0;
            float fromX;
            // 以对角线的长度来做高度,这样可以保证竖屏和横屏整个屏幕都能布满水印
            for (int positionY = diagonal / 8; positionY <= diagonal; positionY += diagonal / 8) {
                fromX = -width + (index++ % 2) * textWidth; // 上下两行的X轴起始点不一样,错开显示
                for (float positionX = fromX; positionX < width; positionX += textWidth * 2) {
                    canvas.drawText(mText, positionX, positionY, mPaint);
                }
            }
            canvas.save();
            canvas.restore();
        }

        @Override
        public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
        }

        @Override
        public void setColorFilter(ColorFilter colorFilter) {
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }

    }
}

使用方法:

 WatermarkUtil.getInstance()
                    .setText("需要显示的内容")
                    .setTextColor(Color.parseColor("#cceeeeee"))
                    .setTextSize(40)
                    .setRotation(-15f)
                    .show(viewGroup);

方法二:布局中实现,水印在内容下面

下面是自定义控件,可以显示在任何布局中,是ViewGroup

**
 * Des: 水印ViewGroup
 * Created by ww on 2020/11/14.
 */
public class WaterMarkViewGroup extends FrameLayout {

    private int mDrawWidth = 300;//画的宽度 为实际高度的mScaleSize倍(作用是在旋转后防止有些地方没有水印)
    private int mDrawHeight = 300;//画的高度 同上
    private String str = "信随行";//水印文字
    private float hSpace = 50f;//水平间距
    private float vSpace = 20f;//垂直间距
    private int mScaleSize = 2;//缩放大小 固定:2
    private int mDegrees = -30;//旋转角度
    private int bgColor = Color.TRANSPARENT;//背景颜色
    private int textColor = Color.BLACK;//字体颜色
    private float textSize = 13f;//字体大小
    private int mWidth;//布局实际宽度
    private int mHeight;//布局实际高度

    public WaterMarkViewGroup(@NonNull Context context) {
        this(context, null);
    }

    public WaterMarkViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    /**
     * 初始化
     *
     * @param context
     * @param attrs
     */
    public void init(Context context, AttributeSet attrs) {
        if (null != attrs) {
            //获取XML中的参数
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WaterMarkView);
            str = ta.getString(R.styleable.WaterMarkView_text);
            hSpace = ta.getDimension(R.styleable.WaterMarkView_hSpace, 50f);
            vSpace = ta.getDimension(R.styleable.WaterMarkView_vSpace, 20f);
            mDegrees = ta.getInteger(R.styleable.WaterMarkView_degrees, -30);
            bgColor = ta.getColor(R.styleable.WaterMarkView_bgColor, Color.TRANSPARENT);
            textColor = ta.getColor(R.styleable.WaterMarkView_textColor, Color.BLACK);
            textSize = ta.getDimension(R.styleable.WaterMarkView_textSize, 13f);
            ta.recycle();
        }
    }

    /**
     * 设置参数
     *
     * @param text 水印文字
     */
    public void setParams(String text) {
        setParams(text, hSpace, vSpace);
    }

    /**
     * 设置参数
     *
     * @param text  水印文字
     * @param hSize 水平方向水印文字个数
     * @param vSize 垂直方向水印文字个数
     */
    public void setParams(String text, float hSize, float vSize) {
        setParams(text, hSize, vSize, mDegrees);
    }

    /**
     * 设置参数
     *
     * @param text    水印文字
     * @param hSize   水平方向水印文字个数
     * @param vSize   垂直方向水印文字个数
     * @param degrees 旋转角度
     */
    public void setParams(String text, float hSize, float vSize, int degrees) {
        setParams(text, hSize, vSize, degrees, bgColor, textColor, textSize);
    }

    /**
     * 参数设置
     *
     * @param text
     * @param hSize
     * @param vSize
     * @param degrees
     * @param bgColor   背景颜色
     * @param textColor 字体颜色
     * @param textSize  字体大小
     */
    public void setParams(String text, float hSize, float vSize, int degrees, int bgColor, int textColor, float textSize) {
        this.str = text;
        this.hSpace = hSize;
        this.vSpace = vSize;
        this.mDegrees = degrees;
        this.bgColor = bgColor;
        this.textColor = textColor;
        this.textSize = textSize;
        invalidate();
    }

    /**
     * 在View的源码当中并没有对AT_MOST和EXACTLY两个模式做出区分,
     * 也就是说View在wrap_content和match_parent两个模式下是完全相同的,
     * 都会是match_parent,
     * 显然这与我们平时用的View不同,
     * 所以我们要重写onMeasure方法。
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mDrawWidth, mDrawHeight);
        } else if (widthMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(mDrawWidth, heightSize);
        } else if (heightMode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(widthSize, mDrawHeight);
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        //获取实际宽高
        mWidth = getWidth();
        mHeight = getHeight();
        //设置需要画的宽高
        mDrawWidth = mWidth * mScaleSize;
        mDrawHeight = mHeight * mScaleSize;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        drawWaterMark(canvas);
        super.dispatchDraw(canvas);
    }

    /**
     * 绘制水印
     *
     * @param canvas
     */
    private void drawWaterMark(Canvas canvas) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        Rect rect = new Rect();
        paint.setTextSize(textSize);
        //获取文字长度和宽度
        paint.getTextBounds(str, 0, str.length(), rect);
        int textWidth = rect.width();
        int textHeight = rect.height();
        //获取每个单独的item的宽高
        float itemWidth = textWidth + hSpace;
        float itemHeight = textHeight + vSpace;
        //获取水平、垂直方向需要绘制的个数
        int hSize = (int) ((mDrawWidth / itemWidth) + 0.5);
        int vSize = (int) ((mDrawHeight / itemHeight) + 0.5);

        //X轴开始坐标
        float xStart = hSpace / 2;
        //Y轴开始坐标
        float yStart = vSpace / 2 + textHeight;

        //创建透明画布
        canvas.drawColor(bgColor);

        paint.setColor(textColor);
        //paint.setAlpha((int) (0.1 * 255));
        // 获取跟清晰的图像采样
        paint.setDither(true);
        paint.setFilterBitmap(true);

        canvas.save();
        //平移
        canvas.translate(-(mDrawWidth / 4), -(mDrawHeight / 4));
        //旋转对应角度
        canvas.rotate(mDegrees, mDrawWidth / 2, mDrawHeight / 2);
        //画X轴方向
        for (int i = 0; i < hSize; i++) {
            float xDraw = xStart + itemWidth * i;
            //画Y轴方向
            for (int j = 0; j < vSize; j++) {
                float yDraw = yStart + itemHeight * j;
                canvas.drawText(str, xDraw, yDraw, paint);
            }
        }
        canvas.restore();
    }
}

涉及到的自定义参数:

 <!--    水印参数-->
    <declare-styleable name="WaterMarkView">
        <!--        水印文字-->
        <attr name="text" format="string" />
        <!--        水平间距-->
        <attr name="hSpace" format="dimension" />
        <!--        垂直间距-->
        <attr name="vSpace" format="dimension" />
        <!--        角度-->
        <attr name="degrees" format="integer" />
        <!--        背景颜色-->
        <attr name="bgColor" format="color" />
        <!--        文字颜色-->
        <attr name="textColor" format="color" />
        <!--        文字大小-->
        <attr name="textSize" format="dimension" />
    </declare-styleable>

将以上在布局底层引用,即可实现底层水印,但是需要在每个添加水印的布局中添加,比较繁琐!

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:41:20  更:2022-02-28 15:42:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 16:08:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码