Based on https://github.com/MostafaGazar/CustomShapeImageView, Custom shape ImageView using PorterDuffXfermode and SVGs as masks
June 4, 2014 ยท View on GitHub
/*
- Copyright 2014 Mostafa Gazar
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License. */
package com.ninja.widget;
import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.graphics.Xfermode; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.ImageView;
import com.larvalabs.svgandroid.SVG; import com.larvalabs.svgandroid.SVGParser; import com.ninja.sms.R; import com.ninja.sms.utils.Log;
import java.lang.ref.WeakReference;
/**
-
@author Mostafa Gazar eng.mostafa.gazar@gmail.com */ public class SvgMaskedImageView extends ImageView {
private static final String TAG = SvgMaskedImageView.class.getSimpleName();
public static final int DEFAULT_SVG_RAW_RES = R.raw.shape_circle;
private int mSvgRawRes = DEFAULT_SVG_RAW_RES;
protected Context mContext;
private static final Xfermode sXfermode = new PorterDuffXfermode(Mode.DST_IN); private Bitmap mMaskBitmap; private Paint mPaint; private WeakReference
mSrcWeakBitmap; private int mLastWidth; private int mLastHeight;
public SvgMaskedImageView(Context context) { super(context);
sharedConstructor(context, null);}
public SvgMaskedImageView(Context context, AttributeSet attrs) { super(context, attrs);
sharedConstructor(context, attrs);}
public SvgMaskedImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle);
sharedConstructor(context, attrs);}
private void sharedConstructor(Context context, AttributeSet attrs) { mContext = context;
mPaint = new Paint(); if (attrs != null) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SvgMaskedImageView); mSvgRawRes = a != null ? a.getResourceId(R.styleable.SvgMaskedImageView_mask, DEFAULT_SVG_RAW_RES) : DEFAULT_SVG_RAW_RES; a.recycle(); }}
public static void drawBitmap(Canvas canvas, Bitmap bitmap, Paint paint) { drawBitmap(canvas, bitmap, paint, 0, 0); }
public static void drawBitmap(Canvas canvas, Bitmap bitmap, Paint paint, int left, int top) { paint.reset(); paint.setFilterBitmap(false); paint.setXfermode(sXfermode);
canvas.drawBitmap(bitmap, left, top, paint);}
public void invalidate() { mSrcWeakBitmap = null; if (mMaskBitmap != null) { mMaskBitmap.recycle(); } mLastWidth = 0; mLastHeight = 0;
super.invalidate();}
@SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { if (!isInEditMode()) { int width = getWidth(); int height = getHeight();
int i = canvas.saveLayer(0.0F, 0.0F, width, height, null, Canvas.ALL_SAVE_FLAG); try { Bitmap srcBitmap = mSrcWeakBitmap != null ? mSrcWeakBitmap.get() : null; if (srcBitmap == null || srcBitmap.isRecycled()) { Drawable srcDrawable = getDrawable(); if (srcDrawable != null) { srcBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas srcBitmapCanvas = new Canvas(srcBitmap); srcDrawable.setBounds(0, 0, getWidth(), getHeight()); srcDrawable.draw(srcBitmapCanvas); // Skip and use cached mask. if (mMaskBitmap == null || mMaskBitmap.isRecycled() || mLastWidth != width || mLastHeight != height) { mMaskBitmap = getMask(width, height); } drawBitmap(srcBitmapCanvas, mMaskBitmap, mPaint); mSrcWeakBitmap = new WeakReference<Bitmap>(srcBitmap); } } if (srcBitmap != null) { mPaint.setXfermode(null); canvas.drawBitmap(srcBitmap, 0.0F, 0.0F, mPaint); } } catch (Exception e) { System.gc(); Log.e(TAG, String.format("Unable to draw, view Id :: %s. Error occurred :: %s", getId(), e.toString())); } finally { canvas.restoreToCount(i); } } else { super.onDraw(canvas); }}
private Bitmap getDefaultMask(int width, int height) { Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK); canvas.drawRect(new RectF(0.0F, 0.0F, width, height), paint);
return bitmap;}
private Bitmap getMask(int width, int height) { SVG svgMask = null; if (mLastWidth != width || mLastHeight != height) { svgMask = SVGParser.getSVGFromInputStream( mContext.getResources().openRawResource(mSvgRawRes), width, height);
mLastWidth = width; mLastHeight = height; } if (svgMask != null) { Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK); canvas.drawPicture(svgMask.getPicture()); return bitmap; } // In case everything failed, return square. return getDefaultMask(width, height);}
public void updateMask(int svgRawRes) { if (mSvgRawRes != svgRawRes) { mSvgRawRes = svgRawRes;
invalidate(); }}
}