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

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


目录

第一种实现方式

项目中的使用案例

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

前景色样式:



背景色样式:

布局:

  1. <com.bqt.lock.MarkFrameLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. android:id="@+id/mark_layout"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. app:mark_is_foreground="false"
  8. app:mark_show_value="包青天"
  9. app:mark_textcolor="#fff">
  10. <TextView
  11. android:id="@+id/tv"
  12. android:layout_width="match_parent"
  13. android:layout_height="100dp"
  14. android:background="#f00"
  15. android:gravity="center"/>
  16. <ImageView
  17. android:layout_width="match_parent"
  18. android:layout_height="100dp"
  19. android:layout_marginTop="200dp"
  20. android:scaleType="centerCrop"
  21. android:src="@drawable/icon"/>
  22. </com.bqt.lock.MarkFrameLayout>

水印布局 MarkFrameLayout

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

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

  1. public class MarkFrameLayout extends FrameLayout {
  2. private static final int DEFAULT_DEGRESES = -15;//水印倾斜角度
  3. private static final int DEFAULT_MARK_PAINT_COLOR = Color.parseColor("#FFCCCCCC");//水印颜色
  4. private static final int DEFAULT_ALPHA = (int) (0.5 * 255);//水印透明度
  5. private static final String DEFAULT_MARK_SHOW_VALUE = "[水印]";//水印内容
  6. private boolean showMark = true;
  7. private float mMarkTextSize;
  8. private int mMarkTextColor;
  9. private boolean mMarkLayerIsForeground; //水印绘制在控件背景上,还是前景色上
  10. private float mDegrees;
  11. private int mVerticalSpacing;
  12. private int mHorizontalSpacing;
  13. private int mMarkPainAlpha;
  14. private String mMarkValue;
  15. private TextPaint mMarkPaint;
  16. private Bitmap mMarkBitmap;
  17. public MarkFrameLayout(@NonNull Context context) {
  18. this(context, null);
  19. }
  20. public MarkFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
  21. super(context, attrs);
  22. if (showMark) {
  23. int defaultMarkTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics());
  24. int defaultSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics());
  25. TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MarkFrameLayout);
  26. mDegrees = a.getInteger(R.styleable.MarkFrameLayout_mark_rotate_degrees, DEFAULT_DEGRESES);
  27. mMarkTextColor = a.getColor(R.styleable.MarkFrameLayout_mark_textcolor, DEFAULT_MARK_PAINT_COLOR);
  28. mMarkTextSize = a.getDimension(R.styleable.MarkFrameLayout_mark_textsize, defaultMarkTextSize);
  29. mMarkPainAlpha = a.getInt(R.styleable.MarkFrameLayout_mark_alpha, DEFAULT_ALPHA);
  30. mMarkLayerIsForeground = a.getBoolean(R.styleable.MarkFrameLayout_mark_is_foreground, true);//默认绘制在前景色上
  31. mHorizontalSpacing = (int) a.getDimension(R.styleable.MarkFrameLayout_mark_hor_spacing, defaultSpacing);
  32. mVerticalSpacing = (int) a.getDimension(R.styleable.MarkFrameLayout_mark_ver_spacing, defaultSpacing);
  33. mMarkValue = a.getString(R.styleable.MarkFrameLayout_mark_show_value);
  34. mMarkValue = TextUtils.isEmpty(mMarkValue) ? DEFAULT_MARK_SHOW_VALUE : mMarkValue;
  35. a.recycle();
  36. initWaterPaint();
  37. setForeground(new ColorDrawable(Color.TRANSPARENT)); //重置前景色透明
  38. }
  39. }
  40. @Override
  41. public void onDrawForeground(Canvas canvas) {
  42. super.onDrawForeground(canvas);
  43. if (showMark && mMarkLayerIsForeground) {
  44. drawMark(canvas); //绘制前景色
  45. }
  46. }
  47. @Override
  48. protected void onDraw(Canvas canvas) {
  49. super.onDraw(canvas);
  50. if (showMark && !mMarkLayerIsForeground) {
  51. drawMark(canvas); //绘制被景色
  52. }
  53. }
  54. private void initWaterPaint() {
  55. //初始化Mark的Paint
  56. mMarkPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); //mMarkPaint.setAntiAlias(true)
  57. mMarkPaint.setColor(mMarkTextColor);
  58. mMarkPaint.setAlpha(mMarkPainAlpha);
  59. mMarkPaint.setTextSize(mMarkTextSize);
  60. //初始化MarkBitmap
  61. Paint.FontMetrics fontMetrics = mMarkPaint.getFontMetrics();
  62. int textHeight = (int) (fontMetrics.bottom - fontMetrics.top);
  63. int textLength = (int) mMarkPaint.measureText(mMarkValue);
  64. mMarkBitmap = Bitmap.createBitmap(textLength + 2 * mHorizontalSpacing,
  65. textHeight + mVerticalSpacing * 2, Bitmap.Config.ARGB_8888);
  66. Canvas canvas = new Canvas(mMarkBitmap);
  67. canvas.drawText(mMarkValue, mHorizontalSpacing, mVerticalSpacing, mMarkPaint);
  68. }
  69. private void drawMark(Canvas canvas) {
  70. int maxSize = Math.max(getMeasuredWidth(), getMeasuredHeight());
  71. mMarkPaint.setShader(new BitmapShader(mMarkBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
  72. canvas.save();
  73. canvas.translate(-(maxSize - getMeasuredWidth()) / 2, 0);
  74. canvas.rotate(mDegrees, maxSize / 2, maxSize / 2);
  75. canvas.drawRect(new RectF(0, 0, maxSize, maxSize), mMarkPaint);
  76. canvas.restore();
  77. }
  78. public void setShowMark(boolean showMark) {
  79. this.showMark = showMark;
  80. invalidate();
  81. }
  82. }

自定义属性

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="MarkFrameLayout">
  4. <attr name="mark_rotate_degrees" format="integer"/>
  5. <attr name="mark_textcolor" format="color|reference"/>
  6. <attr name="mark_textsize" format="dimension"/>
  7. <attr name="mark_alpha" format="integer"/>
  8. <attr name="mark_is_foreground" format="boolean"/>
  9. <attr name="mark_hor_spacing" format="dimension"/>
  10. <attr name="mark_ver_spacing" format="dimension"/>
  11. <attr name="mark_show_value" format="string"/>
  12. </declare-styleable>
  13. </resources>

第二种实现方式

参考

使用案例

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

自定义 Drawable

  1. public class WaterMarkBg extends Drawable {
  2. private Paint paint = new Paint();
  3. private List<String> labels;
  4. private Context context;
  5. private int degress;//角度
  6. private int fontSize;//字体大小 单位sp
  7. /**
  8. * 初始化构造
  9. *
  10. * @param context 上下文
  11. * @param labels 水印文字列表 多行显示支持
  12. * @param degress 水印角度
  13. * @param fontSize 水印文字大小
  14. */
  15. public WaterMarkBg(Context context, List<String> labels, int degress, int fontSize) {
  16. this.labels = labels;
  17. this.context = context;
  18. this.degress = degress;
  19. this.fontSize = fontSize;
  20. }
  21. @Override
  22. public void draw(@NonNull Canvas canvas) {
  23. int width = getBounds().right;
  24. int height = getBounds().bottom;
  25. canvas.drawColor(Color.TRANSPARENT);
  26. paint.setColor(Color.GRAY);
  27. paint.setAlpha((int) (0.5 * 255));
  28. paint.setAntiAlias(true);
  29. paint.setTextSize(sp2px(context, fontSize));
  30. canvas.save();
  31. canvas.rotate(degress);
  32. float textWidth = paint.measureText(labels.get(0));
  33. int index = 0;
  34. for (int positionY = height / 10; positionY <= height; positionY += height / 10 + 80) {
  35. float fromX = -width + (index++ % 2) * textWidth;
  36. for (float positionX = fromX; positionX < width; positionX += textWidth * 2) {
  37. int spacing = 0;//间距
  38. for (String label : labels) {
  39. canvas.drawText(label, positionX, positionY + spacing, paint);
  40. spacing = spacing + 50;
  41. }
  42. }
  43. }
  44. canvas.restore();
  45. }
  46. @Override
  47. public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
  48. }
  49. @Override
  50. public void setColorFilter(@Nullable ColorFilter colorFilter) {
  51. }
  52. @Override
  53. public int getOpacity() {
  54. return PixelFormat.UNKNOWN;
  55. }
  56. private static int sp2px(Context context, float spValue) {
  57. final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
  58. return (int) (spValue * fontScale + 0.5f);
  59. }
  60. }

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. BZOJ.1061.[NOI2008]志愿者招募(线性规划 对偶原理 单纯形 / 费用流SPFA)

    题目链接 线性规划 用\(A_{ij}=0/1\)表示第\(i\)天\(j\)类志愿者能否被招募,\(x_i\)为\(i\)类志愿者招募了多少人,\(need_i\)表示第\(i\)天需要多少人,\( ...

  2. OpenNI2 + NiTE2开发教程

    发现了一个非常不错的关于自然交互OpeNI2+NiTE2的资源,非常感谢Heresy,这里分享链接: OpenNI 2.x 教学文章(转载自:Heresy博客,地址:https://kheresy.w ...

  3. java并发基础(六)--- 活跃性、性能与可伸缩性

    <java并发编程实战>的第9章主要介绍GUI编程,在实际开发中实在很少见到,所以这一章的笔记暂时先放一放,从第10章开始到第12章是第三部分,也就是活跃性.性能.与测试,这部分的知识偏理 ...

  4. Redis主从同步分析(转)

    一.Redis主从同步原理 1.1 Redis主从同步的过程 配置好slave服务器连接的master后,slave会建立和master的连接,然后发送sync命令.无论是第一次同步建立的连接还是连接 ...

  5. LayoutParams继承于Android.View.ViewGroup.LayoutParams(转)

    LayoutParams相当于一个Layout的信息包,它封装了Layout的位置.高.宽等信息.假设在屏幕上一块区域是由一个Layout占领的,如果将一个View添加到一个Layout中,最好告诉L ...

  6. Bus Blaster v4 design overview

    Bus Blaster v4 design overview Bus Blaster v4 is an experimental, high-speed JTAG debugger for ARM p ...

  7. ubuntu修改时区和时间的方法

    改时区参考 http://blog.sina.com.cn/s/blog_6c9d65a1010145st.html 1.首先查看时区: swfsadmin@swfsubuntu:~$ date -R ...

  8. [SQL ERROR 800]Corresponding types must be compatible in CASE expression.

    SQL应用报错800.Corresponding types must be compatible in CASE expression. 错误描述: 11:00:51  [SELECT - 0 ro ...

  9. C# 地磅串口编程

    C# 地磅串口编程 http://www.cnblogs.com/cancer_xu/archive/2012/09/14/WeighBridge-Com.html http://www.cnblog ...

  10. .Net Discovery 系列之五--深入浅出.Net实时编译机制(上)

    欢迎阅读“.Net Discovery 系列”文章,本文将分上.下两部分为大家讲解.Net JIT方面的知识,敬请雅正. JIT(Just In Time简称JIT)是.Net边运行边编译的一种机制, ...