通过创建一个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次来实现。
运行的效果如下: