Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

自定义View 水印布局 WaterMark 前景色 MD


目录

第一种实现方式

项目中的使用案例

项目中要求在所有页面都添加水印,这种情况下可以在BaseActivity中将水印布局设为根布局

前景色样式:



背景色样式:

布局:

<com.bqt.lock.MarkFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mark_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:mark_is_foreground="false"
app:mark_show_value="包青天"
app:mark_textcolor="#fff"> <TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#f00"
android:gravity="center"/> <ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="200dp"
android:scaleType="centerCrop"
android:src="@drawable/icon"/> </com.bqt.lock.MarkFrameLayout>

水印布局 MarkFrameLayout

绘制水印时,可以选择在onDrawForeground上绘制前景色(盖在所有View的上面),也可以选择在onDraw上绘制背景色(会被所有View的背景遮盖)。

如果需要用到继承自其他其他 Layout 的水印布局,则只需将继承的类改为RelativeLayoutLinearLayout即可,其他什么都不需要更改。

public class MarkFrameLayout extends FrameLayout {

    private static final int DEFAULT_DEGRESES = -15;//水印倾斜角度
private static final int DEFAULT_MARK_PAINT_COLOR = Color.parseColor("#FFCCCCCC");//水印颜色
private static final int DEFAULT_ALPHA = (int) (0.5 * 255);//水印透明度
private static final String DEFAULT_MARK_SHOW_VALUE = "[水印]";//水印内容 private boolean showMark = true;
private float mMarkTextSize;
private int mMarkTextColor;
private boolean mMarkLayerIsForeground; //水印绘制在控件背景上,还是前景色上
private float mDegrees;
private int mVerticalSpacing;
private int mHorizontalSpacing;
private int mMarkPainAlpha;
private String mMarkValue;
private TextPaint mMarkPaint;
private Bitmap mMarkBitmap; public MarkFrameLayout(@NonNull Context context) {
this(context, null);
} public MarkFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
if (showMark) {
int defaultMarkTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics());
int defaultSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics()); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MarkFrameLayout);
mDegrees = a.getInteger(R.styleable.MarkFrameLayout_mark_rotate_degrees, DEFAULT_DEGRESES);
mMarkTextColor = a.getColor(R.styleable.MarkFrameLayout_mark_textcolor, DEFAULT_MARK_PAINT_COLOR);
mMarkTextSize = a.getDimension(R.styleable.MarkFrameLayout_mark_textsize, defaultMarkTextSize);
mMarkPainAlpha = a.getInt(R.styleable.MarkFrameLayout_mark_alpha, DEFAULT_ALPHA);
mMarkLayerIsForeground = a.getBoolean(R.styleable.MarkFrameLayout_mark_is_foreground, true);//默认绘制在前景色上
mHorizontalSpacing = (int) a.getDimension(R.styleable.MarkFrameLayout_mark_hor_spacing, defaultSpacing);
mVerticalSpacing = (int) a.getDimension(R.styleable.MarkFrameLayout_mark_ver_spacing, defaultSpacing);
mMarkValue = a.getString(R.styleable.MarkFrameLayout_mark_show_value);
mMarkValue = TextUtils.isEmpty(mMarkValue) ? DEFAULT_MARK_SHOW_VALUE : mMarkValue; a.recycle();
initWaterPaint();
setForeground(new ColorDrawable(Color.TRANSPARENT)); //重置前景色透明
}
} @Override
public void onDrawForeground(Canvas canvas) {
super.onDrawForeground(canvas);
if (showMark && mMarkLayerIsForeground) {
drawMark(canvas); //绘制前景色
}
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (showMark && !mMarkLayerIsForeground) {
drawMark(canvas); //绘制被景色
}
} private void initWaterPaint() {
//初始化Mark的Paint
mMarkPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); //mMarkPaint.setAntiAlias(true)
mMarkPaint.setColor(mMarkTextColor);
mMarkPaint.setAlpha(mMarkPainAlpha);
mMarkPaint.setTextSize(mMarkTextSize);
//初始化MarkBitmap
Paint.FontMetrics fontMetrics = mMarkPaint.getFontMetrics();
int textHeight = (int) (fontMetrics.bottom - fontMetrics.top);
int textLength = (int) mMarkPaint.measureText(mMarkValue);
mMarkBitmap = Bitmap.createBitmap(textLength + 2 * mHorizontalSpacing,
textHeight + mVerticalSpacing * 2, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mMarkBitmap);
canvas.drawText(mMarkValue, mHorizontalSpacing, mVerticalSpacing, mMarkPaint);
} private void drawMark(Canvas canvas) {
int maxSize = Math.max(getMeasuredWidth(), getMeasuredHeight());
mMarkPaint.setShader(new BitmapShader(mMarkBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
canvas.save();
canvas.translate(-(maxSize - getMeasuredWidth()) / 2, 0);
canvas.rotate(mDegrees, maxSize / 2, maxSize / 2);
canvas.drawRect(new RectF(0, 0, maxSize, maxSize), mMarkPaint);
canvas.restore();
} public void setShowMark(boolean showMark) {
this.showMark = showMark;
invalidate();
}
}

自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MarkFrameLayout">
<attr name="mark_rotate_degrees" format="integer"/>
<attr name="mark_textcolor" format="color|reference"/>
<attr name="mark_textsize" format="dimension"/>
<attr name="mark_alpha" format="integer"/>
<attr name="mark_is_foreground" format="boolean"/>
<attr name="mark_hor_spacing" format="dimension"/>
<attr name="mark_ver_spacing" format="dimension"/>
<attr name="mark_show_value" format="string"/>
</declare-styleable> </resources>

第二种实现方式

参考

使用案例

FrameLayout rootView = findViewById(R.id.layout);
rootView.setForeground(new WaterMarkBg(this, labels, -10, 12));

自定义 Drawable

public class WaterMarkBg extends Drawable {

    private Paint paint = new Paint();
private List<String> labels;
private Context context;
private int degress;//角度
private int fontSize;//字体大小 单位sp /**
* 初始化构造
*
* @param context 上下文
* @param labels 水印文字列表 多行显示支持
* @param degress 水印角度
* @param fontSize 水印文字大小
*/
public WaterMarkBg(Context context, List<String> labels, int degress, int fontSize) {
this.labels = labels;
this.context = context;
this.degress = degress;
this.fontSize = fontSize;
} @Override
public void draw(@NonNull Canvas canvas) {
int width = getBounds().right;
int height = getBounds().bottom; canvas.drawColor(Color.TRANSPARENT);
paint.setColor(Color.GRAY);
paint.setAlpha((int) (0.5 * 255));
paint.setAntiAlias(true);
paint.setTextSize(sp2px(context, fontSize));
canvas.save();
canvas.rotate(degress);
float textWidth = paint.measureText(labels.get(0));
int index = 0;
for (int positionY = height / 10; positionY <= height; positionY += height / 10 + 80) {
float fromX = -width + (index++ % 2) * textWidth;
for (float positionX = fromX; positionX < width; positionX += textWidth * 2) {
int spacing = 0;//间距
for (String label : labels) {
canvas.drawText(label, positionX, positionY + spacing, paint);
spacing = spacing + 50;
} }
}
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.UNKNOWN;
} private static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
}

2018-10-13 11:59:36 星期六

自定义View 水印布局 WaterMark 前景色 MD的更多相关文章

  1. android自定义View&&简单布局&&回调方法

    一.内容描述 根据“慕课网”上的教程,实现一个自定义的View,且该View中使用自定义的属性,同时为该自定义的View定义点击事件的回调方法. 二.定义自定义的属性 在res/valus/ 文件夹下 ...

  2. Android 自定义View及其在布局文件中的使用示例

    前言: 尽管Android已经为我们提供了一套丰富的控件,如:Button,ImageView,TextView,EditText等众多控件,但是,有时候在项目开发过程中,还是需要开发者自定义一些需要 ...

  3. 【朝花夕拾】Android自定义View篇之(九)多点触控(下)实践出真知

    前言 在上一篇文章中,已经总结了MotionEvent以及多点触控相关的基础理论知识和常用的函数.本篇将通过实现单指拖动图片,多指拖动图片的实际案例来进行练习并实现一些效果,来理解前面的理论知识.要理 ...

  4. 自定义View实现五子棋游戏

    成功的路上一点也不拥挤,因为坚持的人太少了. ---简书上看到的一句话 未来请假三天顺带加上十一回家结婚,不得不说真是太坑了,去年婚假还有10天,今年一下子缩水到了3天,只能赶着十一办事了. 最近还在 ...

  5. 自定义View的实现流程

    1.继承View组件,比如,LabelView继承了View   2.重写两个构造方法,比如,对于自定义View LabelView   LabelView(Context context),如果该自 ...

  6. Android圆形图片不求人,自定义View实现(BitmapShader使用)

    在很多APP当中,圆形的图片是必不可少的元素,美观大方.本文将带领读者去实现一个圆形图片自定View,力求只用一个Java类来完成这件事情. 一.先上效果图 二.实现思路 在定义View 的onMea ...

  7. html页面自定义文字水印效果案例

    在系统开发过程中,一些数据或页面比较敏感的地方,客户会要求实现水印效果,防止内部人员截图或拍照泄露信息. 自定义文字水印顾名思义就是利用js在完成页面渲染的同时,往页面的最底层动态生成多个带水印信息的 ...

  8. Android 自定义View及其在布局文件中的使用示例(三):结合Android 4.4.2_r1源码分析onMeasure过程

    转载请注明出处 http://www.cnblogs.com/crashmaker/p/3549365.html From crash_coder linguowu linguowu0622@gami ...

  9. Android 自定义View及其在布局文件中的使用示例(二)

    转载请注明出处 http://www.cnblogs.com/crashmaker/p/3530213.html From crash_coder linguowu linguowu0622@gami ...

随机推荐

  1. Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP

    题意: 给一个$n$点$m$边的连通图 每个边有一个权值$d$ 当且仅当当前走过的步数$\ge d$时 才可以走这条边 问从节点$1$到节点$n$的最短路 好神的一道题 直接写做法喽 首先我们对边按$ ...

  2. Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined) B. Code obfuscation 水题

    B. Code obfuscation 题目连接: http://codeforces.com/contest/765/problem/B Description Kostya likes Codef ...

  3. Slickflow.NET 开源工作流引擎基础介绍(十) -- 邮件轮询异步发送模块集成

    前言:在任务数据生成时,为了让办理任务的用户及时获取到待办任务的主题和内容,需要发送通知类的消息,而电子邮件和手机端的短信通知则是比较普通的消息发送.本文是针对电子邮件异步发送模块的实现来做实例说明. ...

  4. Failed to connect socket to '/var/run/libvirt/libvirt-sock'的问题解决

    1.增加libvirtd用户组 groupadd libvirtd 2.设置用户到组 sudo usermod -a -G libvirtd $USER 3.设置启动libvirtd服务的用户组 vi ...

  5. 【转载】Android dip,px,pt,sp 的区别

     dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这个,不依赖像素. ...

  6. 给Eclipse安装eUML2插件以及可能出现的依赖错误解决方案(转)

    eUML2是一款强大的,基于Eclipse应用程序的UML建模工具.开发者可以在UML开发过程中将模型转化为Java代码:确保软件质量和减少开发时间. 必备条件 Java runtime 1.5 or ...

  7. POJ 1741 Tree (树分治入门)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 8554   Accepted: 2545 Description ...

  8. Java集合框架顶层接口collectiion接口

    如何使用迭代器 通常情况下,你会希望遍历一个集合中的元素.例如,显示集合中的每个元素. 一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合 ...

  9. Android App组件之Activity

    Android App组件之Activity 1 activit介绍 Activities 是Android的四大组件之一,其余三大组件是service.broadcast和content provi ...

  10. iOS 字符串 中包含 % 百分号的方法

    百分号的转换,NSString中需要格式化的字符串中百分号使用%%表示,而char*中百分号也是使用%%表示. 例如:NSLog(@"%%%@%%",@"hello&qu ...