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次來實現。

運行的效果如下:
在這裏插入圖片描述

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