在项目开发进行中,要求给商品图片添加水印。有什么好办法呢?搜索网上的大致有两种方案
- ImageView视图加载出现之后在进行加载
- 在布局中写布局文件实现
以上两种方案都不能很好的满足项目的需要,所以就考虑到重写ImageView,在onDraw方法中做事情
- WatermarkImageView继承ImageView
public class WatermarkImageView extends AppCompatImageView {
private Bitmap mWatemarkBitmap;
private RectF srcRect;
private PorterDuffXfermode mXfermode;
public WatermarkImageView(Context context) {
this(context, null);
}
public WatermarkImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WatermarkImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
init();
}
/**
* 默认资源初始化
*/
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_prologo);
}
}
- 重写onDraw()方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 创建水印图层
int i = canvas.saveLayer(srcRect, mPaint, Canvas.ALL_SAVE_FLAG);
// 设置模式,为直接覆盖到原图
mPaint.setXfermode(mXfermode);
// 绘制水印到当前图层
canvas.drawBitmap(mWatemarkBitmap, null, srcRect, mPaint);
// 清除模式
mPaint.setXfermode(null);
// 将如上画的层覆盖到原有层级上
canvas.restoreToCount(i);
}
-
设置属性
1.arrays.xml文件内容<declare-styleable name="WatermarkImageView"> <attr name="watermark_width" format="dimension" /> <attr name="watermark_height" format="dimension" /> <attr name="watermark_visible" format="boolean" /> <attr name="watermark_padding_top" format="dimension" /> <attr name="watermark_padding_right" format="dimension" /> <attr name="watermark_padding_left" format="dimension" /> <attr name="watermark_padding_bottom" format="dimension" /> <attr name="watermark_src" format="reference" /> <attr name="watermark_location" format="enum"> <enum name="locate_left_to_top" value="0" /> <enum name="locate_right_to_top" value="1" /> <enum name="locate_left_to_bottom" value="2" /> <enum name="locate_right_to_bottom" value="3" /> <enum name="locate_center" value="4" /> </attr> </declare-styleable>
2.代码获取属性
/** * 从xml文件中获取属性 * * @param attrs attrs */ private void initAttribute(AttributeSet attrs) { TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.WatermarkImageView); int N = typedArray.getIndexCount(); for (int i = 0; i < N; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.WatermarkImageView_watermark_src: // Bitmap bitmap = ((BitmapDrawable) typedArray.getDrawable(attr)).getBitmap(); int resourceId = typedArray.getResourceId(attr, R.drawable.ic_prologo); mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), resourceId); break; case R.styleable.WatermarkImageView_watermark_visible: mIsWatermark = typedArray.getBoolean(R.styleable.WatermarkImageView_watermark_visible, false); break; case R.styleable.WatermarkImageView_watermark_width: mWatermarkWidth = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_width, -1); Log.d("mWatermarkWidth" + mWatermarkWidth); break; case R.styleable.WatermarkImageView_watermark_height: mWatermarkHeight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_height, -1); Log.d("mWatermarkHeight" + mWatermarkHeight); break; case R.styleable.WatermarkImageView_watermark_padding_top: mWatermarkPaddingTop = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_top, -1); Log.d("mWatermarkPaddingTop" + mWatermarkPaddingTop); break; case R.styleable.WatermarkImageView_watermark_padding_right: mWatermarkPaddingRight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_right, -1); Log.d("mWatermarkPaddingRight" + mWatermarkPaddingRight); break; case R.styleable.WatermarkImageView_watermark_padding_left: mWatermarkPaddingLeft = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_left, -1); Log.d("mWatermarkPaddingLeft" + mWatermarkPaddingLeft); break; case R.styleable.WatermarkImageView_watermark_padding_bottom: mWatermarkPaddingBottom = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_bottom, -1); Log.d("mWatermarkPaddingBottom" + mWatermarkPaddingBottom); break; case R.styleable.WatermarkImageView_watermark_location: mCurrentLocate = typedArray.getInteger(R.styleable.WatermarkImageView_watermark_location, mCurrentLocate); Log.d("mCurrentLocate" + mCurrentLocate); break; default: break; } } typedArray.recycle(); }
-
完整代码
package com.pbs.xpjx.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.annotation.IntDef;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import com.bsh.sdk.utils.DisplayUtil;
import com.pbs.xpjx.R;
import com.pbs.xpjx.utils.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* 图片添加水印(目前该view只支持添加图片,后续如需要添加文字可以继续添加)
* Created by timmy.tan on 2017/11/23.
*/
public class WatermarkImageView extends AppCompatImageView {
public static final int LOCATE_LEFT_TO_TOP = 0; // 左上
public static final int LOCATE_RIGHT_TO_TOP = 1; // 右上
public static final int LOCATE_LEFT_TO_BOTTOM = 2; // 左下
public static final int LOCATE_RIGHT_TO_BOTTOM = 3; // 右下
public static final int LOCATE_CENTER = 4; // 居中
@IntDef({LOCATE_LEFT_TO_TOP, LOCATE_RIGHT_TO_TOP, LOCATE_LEFT_TO_BOTTOM, LOCATE_RIGHT_TO_BOTTOM, LOCATE_CENTER})
@Retention(RetentionPolicy.SOURCE)
public @interface Locate {
}
@Locate
int mCurrentLocate = LOCATE_RIGHT_TO_TOP;
private Context mContext;
private Paint mPaint;
private int mScale = 5; // 设置水印图与原图的比例
private Bitmap mWatemarkBitmap;
private RectF srcRect;
private PorterDuffXfermode mXfermode;
private boolean mIsWatermark = false;
private int mWatermarkWidth = -1; // 水印宽度
private int mWatermarkHeight = -1; // 水印高度
private int mWatermarkPaddingTop;
private int mWatermarkPaddingRight;
private int mWatermarkPaddingLeft;
private int mWatermarkPaddingBottom;
public WatermarkImageView(Context context) {
this(context, null);
}
public WatermarkImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WatermarkImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
init();
initAttribute(attrs);
}
/**
* 默认资源初始化
*/
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_prologo);
}
/**
* 从xml文件中获取属性
*
* @param attrs attrs
*/
private void initAttribute(AttributeSet attrs) {
TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.WatermarkImageView);
int N = typedArray.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.WatermarkImageView_watermark_src:
// Bitmap bitmap = ((BitmapDrawable) typedArray.getDrawable(attr)).getBitmap();
int resourceId = typedArray.getResourceId(attr, R.drawable.ic_prologo);
mWatemarkBitmap = BitmapFactory.decodeResource(getResources(), resourceId);
break;
case R.styleable.WatermarkImageView_watermark_visible:
mIsWatermark = typedArray.getBoolean(R.styleable.WatermarkImageView_watermark_visible, false);
break;
case R.styleable.WatermarkImageView_watermark_width:
mWatermarkWidth = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_width, -1);
Log.d("mWatermarkWidth" + mWatermarkWidth);
break;
case R.styleable.WatermarkImageView_watermark_height:
mWatermarkHeight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_height, -1);
Log.d("mWatermarkHeight" + mWatermarkHeight);
break;
case R.styleable.WatermarkImageView_watermark_padding_top:
mWatermarkPaddingTop = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_top, -1);
Log.d("mWatermarkPaddingTop" + mWatermarkPaddingTop);
break;
case R.styleable.WatermarkImageView_watermark_padding_right:
mWatermarkPaddingRight = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_right, -1);
Log.d("mWatermarkPaddingRight" + mWatermarkPaddingRight);
break;
case R.styleable.WatermarkImageView_watermark_padding_left:
mWatermarkPaddingLeft = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_left, -1);
Log.d("mWatermarkPaddingLeft" + mWatermarkPaddingLeft);
break;
case R.styleable.WatermarkImageView_watermark_padding_bottom:
mWatermarkPaddingBottom = typedArray.getLayoutDimension(R.styleable.WatermarkImageView_watermark_padding_bottom, -1);
Log.d("mWatermarkPaddingBottom" + mWatermarkPaddingBottom);
break;
case R.styleable.WatermarkImageView_watermark_location:
mCurrentLocate = typedArray.getInteger(R.styleable.WatermarkImageView_watermark_location, mCurrentLocate);
Log.d("mCurrentLocate" + mCurrentLocate);
break;
default:
break;
}
}
typedArray.recycle();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 不设置宽高默认按比例计算
if (mWatermarkWidth < 0) {
mWatermarkWidth = w / mScale;
}
if (mWatermarkHeight < 0) {
mWatermarkHeight = h / mScale;
}
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
switch (mCurrentLocate) {
case LOCATE_LEFT_TO_TOP:
// 左上
left = mWatermarkPaddingLeft;
top = mWatermarkPaddingTop;
right = mWatermarkWidth + mWatermarkPaddingLeft;
bottom = mWatermarkHeight + mWatermarkPaddingTop;
break;
case LOCATE_RIGHT_TO_TOP:
// 右上
left = w - mWatermarkWidth - mWatermarkPaddingRight;
top = mWatermarkPaddingTop;
right = left + mWatermarkWidth;
bottom = top + mWatermarkHeight;
break;
case LOCATE_LEFT_TO_BOTTOM:
// 左下
left = mWatermarkPaddingLeft;
top = h - mWatermarkPaddingBottom - mWatermarkHeight;
right = left + mWatermarkWidth;
bottom = h - mWatermarkPaddingBottom;
break;
case LOCATE_RIGHT_TO_BOTTOM:
// 右下
left = w - mWatermarkPaddingRight - mWatermarkWidth;
top = h - mWatermarkPaddingBottom - mWatermarkHeight;
right = w - mWatermarkPaddingRight;
bottom = h - mWatermarkPaddingBottom;
break;
case LOCATE_CENTER:
// 居中
int parentHalfW = w >> 1;
int watermarkHalfW = mWatermarkWidth >> 1;
int parentHalfH = h >> 1;
int watermarkHalfH = mWatermarkHeight >> 1;
left = parentHalfW - watermarkHalfW;
top = parentHalfH - watermarkHalfH;
right = parentHalfW + watermarkHalfW;
bottom = parentHalfH + watermarkHalfH;
break;
default:
break;
}
srcRect = new RectF(left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (false) {
drawWatermark(canvas);
}
}
/**
* 画水印
*
* @param canvas canvas
*/
private void drawWatermark(Canvas canvas) {
// 创建水印图层
int i = canvas.saveLayer(srcRect, mPaint, Canvas.ALL_SAVE_FLAG);
// 设置模式,为直接覆盖到原图
mPaint.setXfermode(mXfermode);
// 绘制水印到当前图层
canvas.drawBitmap(mWatemarkBitmap, null, srcRect, mPaint);
// 清除模式
mPaint.setXfermode(null);
// 将如上画的层覆盖到原有层级上
canvas.restoreToCount(i);
}
/**
* 是否显示水印
*
* @param b true 显示 false 不显示
*/
public void showWatermark(boolean b) {
this.mIsWatermark = b;
// 视图重绘,执行onDraw()方法
invalidate();
}
public Bitmap getWatemarkBitmap() {
return mWatemarkBitmap;
}
public void setWatemarkBitmap(Bitmap mWatemarkBitmap) {
this.mWatemarkBitmap = mWatemarkBitmap;
invalidate();
}
public int getWatermarkWidth() {
return mWatermarkWidth;
}
public void setWatermarkWidth(int mWatermarkWidth) {
this.mWatermarkWidth = mWatermarkWidth;
invalidate();
}
public int getWatermarkHeight() {
return mWatermarkHeight;
}
public void setWatermarkHeight(int mWatermarkHeight) {
this.mWatermarkHeight = mWatermarkHeight;
invalidate();
}
public int getCurrentLocate() {
return mCurrentLocate;
}
public void setCurrentLocate(@Locate int mCurrentLocate) {
this.mCurrentLocate = mCurrentLocate;
invalidate();
}
}
- 使用指南
<xxx.WatermarkImageView
android:id="@+id/iv_photo"
android:layout_width="90dp"
android:layout_height="90dp"
android:background="@drawable/divider_color_round_rect"
android:scaleType="centerCrop"
android:src="@mipmap/normal_product"
app:watermark_padding_right="10dp"
app:watermark_padding_top="10dp" />
网友评论