来源:https://blog.csdn.net/fantasy_lin_/article/details/97651171
https://blog.51cto.com/u_16213318/11745242
为了能够方便地在任意页面上加水印,所以应该采取用Java代码来实现,而不是在XML布局文件里面写。大概思路是,首先获取当前页面的底层布局,然后在布局最上层添加一个全屏的带有水印的FrameLayout布局。这个全屏的带有水印的FrameLayout布局,我们可以在XML写。很多博客文章都是介绍这种方式来写水印,不过大多数都没做适配,特别是横屏显示时,水印效果很不好。所以我这里用Java代码来画水印。自定义一个Drawable,把它当作水印,然后设置到FrameLayout布局的背景,这样就行了。
特别注意:以下方法添加的水印会覆盖到画面上,可以调节透明度来调整水印对页面内容的遮挡。
如果使用rootView.addView(layout,0);把水印视图添加到根视图中的底层,那么水印会被上层组件覆盖,达不到效果。
相关代码如下所示:
https://blog.51cto.com/u_16213318/11745242
为了能够方便地在任意页面上加水印,所以应该采取用Java代码来实现,而不是在XML布局文件里面写。大概思路是,首先获取当前页面的底层布局,然后在布局最上层添加一个全屏的带有水印的FrameLayout布局。这个全屏的带有水印的FrameLayout布局,我们可以在XML写。很多博客文章都是介绍这种方式来写水印,不过大多数都没做适配,特别是横屏显示时,水印效果很不好。所以我这里用Java代码来画水印。自定义一个Drawable,把它当作水印,然后设置到FrameLayout布局的背景,这样就行了。
特别注意:以下方法添加的水印会覆盖到画面上,可以调节透明度来调整水印对页面内容的遮挡。
如果使用rootView.addView(layout,0);把水印视图添加到根视图中的底层,那么水印会被上层组件覆盖,达不到效果。
相关代码如下所示:
package com.fantasy.blogdemo.utils; import android.app.Activity; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; 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.view.ViewGroup; import android.widget.FrameLayout; /** * 水印 * <pre> * author : Fantasy * version : 1.0, 2019-07-29 * since : 1.0, 2019-07-29 * </pre> */ public class Watermark { /** * 水印文本 */ private String mText; /** * 字体颜色,十六进制形式,例如:0xAEAEAEAE */ private int mTextColor; /** * 字体大小,单位为sp */ private float mTextSize; /** * 旋转角度 */ private float mRotation; private static Watermark sInstance; private Watermark() { mText = ""; mTextColor = 0xAEAEAEAE; mTextSize = 18; mRotation = -25; } public static Watermark getInstance() { if (sInstance == null) { synchronized (Watermark.class) { sInstance = new Watermark(); } } return sInstance; } /** * 设置水印文本 * * @param text 文本 * @return Watermark实例 */ public Watermark setText(String text) { mText = text; return sInstance; } /** * 设置字体颜色 * * @param color 颜色,十六进制形式,例如:0xAEAEAEAE * @return Watermark实例 */ public Watermark setTextColor(int color) { mTextColor = color; return sInstance; } /** * 设置字体大小 * * @param size 大小,单位为sp * @return Watermark实例 */ public Watermark setTextSize(float size) { mTextSize = size; return sInstance; } /** * 设置旋转角度 * * @param degrees 度数 * @return Watermark实例 */ public Watermark 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); } 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(@NonNull Canvas canvas) { int width = getBounds().right; int height = getBounds().bottom; int diagonal = (int) Math.sqrt(width * width + height * height); // 对角线的长度 mPaint.setColor(mTextColor); mPaint.setTextSize(ConvertUtils.spToPx(mTextSize)); // ConvertUtils.spToPx()这个方法是将sp转换成px,ConvertUtils这个工具类在我提供的demo里面有 mPaint.setAntiAlias(true); float textWidth = mPaint.measureText(mText); canvas.drawColor(0x00000000); canvas.rotate(mRotation); int index = 0; float fromX; // 以对角线的长度来做高度,这样可以保证竖屏和横屏整个屏幕都能布满水印 for (int positionY = diagonal / 10; positionY <= diagonal; positionY += diagonal / 10) { 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(@Nullable ColorFilter colorFilter) { } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } } }
使用方式:为了保证能够在当前页面的最顶层加水印,应该在 setContentView() 后面添加水印
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Watermark.getInstance().show(this, "Fantasy BlogDemo"); // 可以自定义水印文字颜色、大小和旋转角度 //Watermark.getInstance() // .setText("Fantasy BlogDemo") // .setTextColor(0xAE000000) // .setTextSize(16) // .setRotation(-30) // .show(this); }
git:https://github.com/FantasyLWX/BlogDemo/blob/master/app/src/main/java/com/fantasy/blogdemo/utils/Watermark.java
dp、px、sp互转
/** * Value of dp to value of px. * * @param dpValue The value of dp. * @return value of px */ public static int dpToPx(float dpValue) { float scale = Resources.getSystem().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * Value of px to value of dp. * * @param pxValue The value of px. * @return value of dp */ public static int pxToDp(float pxValue) { float scale = Resources.getSystem().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * 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); } /** * Value of px to value of sp. * * @param pxValue The value of px. * @return value of sp */ public static int pxToSp(float pxValue) { float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; return (int) (pxValue / fontScale + 0.5f); }