Android实现水印背景功能(不是通过旋转canvas实现)

通过创建一个Drawable,设置成页面的背景。
大概的思路:R.android.id.content拿到布局Layout,然后添加一个FrameLayout背景有水印的View到布局文件中。

代码如下(Android9.0上测试通过)

package com.example.customview.watermark;

import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.example.utils.GetTime;

import java.lang.ref.WeakReference;

/**
 * @author gq
 * 实现背景水印效果
 */
public class WaterMark {
    private static final String TAG = "WaterMark";

    /** 当前内容不能换行,使用2个变量实现 。后续可以优化*/
    private String mText;//水印内容
    private String mTime;//水印时间

    private int mTextColor;//字体颜色,例如:0x10000000,10表示透明度
    private float mTextSize;//字体大小,单位为sp
    private int mAlpha ;//文字透明度
    private float mRotation;//旋转角度

    private static WaterMark sInstance;//使用单例模式

    private WaterMark() {
        mText = "";
        mTime = new GetTime().getTimeFormat12();//这个是返回一个当前的时间:2020/04/08。
        mAlpha = 20;
        mTextColor = 0x10000000;
        mTextSize = 14;
        mRotation = -20;
    }

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

    /** 设置水印文本 */
    public WaterMark setText(String text) {
        mText = text;
        return sInstance;
    }

    /** 设置水印时间 */
    public WaterMark setTime(String time) {
        mTime = time;
        return sInstance;
    }

    /** 设置透明度 */
    public WaterMark setAlpha(int alpha) {
        mAlpha = alpha;
        return sInstance;
    }

    /** 设置字体颜色 */
    public WaterMark setTextColor(int color) {
        mTextColor = color;
        return sInstance;
    }

    /** 设置字体大小 */
    public WaterMark setTextSize(float size) {
        mTextSize = size;
        return sInstance;
    }

    /** 设置旋转角度 */
    public WaterMark setRotation(float degrees) {
        mRotation = degrees;
        return sInstance;
    }

    /** 显示水印,铺满整个页面 */
    public void show(Activity activity) {
        WeakReference<Activity> mActivity  = new WeakReference<>(activity);//使用弱引用,避免内存泄漏
        if(null != mActivity.get()){
            show(mActivity.get(), mText);
        }
    }

    /**
     * 显示水印,铺满整个页面
     *
     * @param activity 活动
     * @param text     水印
     */
    public void show(Activity activity, String text) {
        WeakReference<Activity> mActivity  = new WeakReference<>(activity);//使用弱引用,避免内存泄漏
        if(null == mActivity.get()){
            return;
        }

        setText(text);
        WatermarkDrawable drawable = new WatermarkDrawable();

        ViewGroup rootView = mActivity.get().findViewById(android.R.id.content);
        FrameLayout layout = new FrameLayout(mActivity.get());
        layout.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        layout.setBackground(drawable);
        rootView.addView(layout);
    }

    private class WatermarkDrawable extends Drawable {
        private Paint mPaint;

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

        @Override
        public void draw(@NonNull Canvas canvas) {
            int width = getBounds().right;
            int height = getBounds().bottom;

            mPaint.setColor(mTextColor);
            mPaint.setTextSize(ConvertUtils.spToPx(mTextSize)); // ConvertUtils.spToPx()这个方法是将sp转换成px,ConvertUtils这个工具类在我提供的demo里面有
            mPaint.setAntiAlias(true);
            float textWidth = mPaint.measureText(mText);
            Log.d(TAG,"width = " + width + " || height = " + height + "|| textWidth = " + textWidth);

            canvas.drawColor(0x00000000);
//            canvas.rotate(mRotation);//设置画布旋转


            mPaint.setAlpha(mAlpha);
            int initHeigh = 200;
            for (int columnLineCount = 0; columnLineCount < 6; columnLineCount++) {
                for (int rowLineCount = 0; rowLineCount <3 ; rowLineCount++) {
                    Path path = new  Path();
                    //设置起始点
                    path.moveTo(rowLineCount*400, initHeigh + (height/5)*columnLineCount);
                    //线的起点就是moveTo 设置的点
                    path.lineTo(textWidth + rowLineCount*400,initHeigh + (height/5)*columnLineCount-textWidth/4);
                    canvas.drawPath(path,mPaint);

                    /** 开始画文本 */
                    canvas.drawTextOnPath(mText,path,0,0,mPaint);//hOffset水平偏移量
                    canvas.drawTextOnPath(mTime,path,0,50,mPaint);//vOffset垂直偏移量,实现文本的换行
                }
            }

//                    canvas.drawText(mText, positionX, positionY, mPaint);
//                    canvas.drawText("2020/04/07", positionX, positionY+60, mPaint);

            canvas.save();
            canvas.restore();
        }

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

        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {
        }

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

    }
}

工具方法:

/**
* Value of sp to value of px.
*
* @param spValue The value of sp.
* @return value of px
*/
public static int spToPx(float spValue) {
	float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity;
	return (int) (spValue * fontScale + 0.5f);
}

调用的方法:(在Activity的onCreate回调中使用即可)

//方式一,使用默认的配置
WaterMark.getInstance().show(this, “test”);

//方式二,使用自定义配置
WaterMark.getInstance()
	.setText("water mark")
	.setTextColor(0x10000000)
	.setTextSize(14)
	.setRotation(-10)
	.show(this);

备注:这里我并没有使用旋转cavas来实现文字的旋转(如果多行,每一行不是对齐的,不好计算x轴的偏移量)。而是通过canvas.drawTextOnPath这个方法,旋转文字。这个里面的逻辑并没有封装,而是直接写了些固定的大小。有兴趣的同学可以封装成方法。例如可以设置文字的旋转角度。

drawTextOnPath这个方法不支持文字换行,暂且的解决方法就是通过画2次来实现。

运行的效果如下:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章