通過創建一個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次來實現。
運行的效果如下: