Android Xfermode implements circular and rounded image,
Reprinted please indicate the source: bytes]
1. Overview
In fact, this article was originally prepared for Android BitmapShader to implement a circular and rounded image and put it in one article. As a result, it was released independently due to space reasons ~ A long time ago, I wrote a circular and rounded image using Xfermode, but the image inherits the View. In fact, it is convenient to inherit the ImageView, and at least the onMeasure policy is saved, and you do not need to provide the image setting method by yourself. The most important thing is that you are familiar with the ImageView API and can use it easily.
Okay, this article is a record ~~~ I can't find the code on my computer after a few days. I still need to post it on my blog. You need to come and check it out ~~~
2. Principles
I will not talk about the principle. This figure appears more than three times in my blog. We use DST_IN this mode, which is to draw the image first and then draw the shape ~~
3. Xfermode Practice 1. Custom Attributes
First, it is still a custom attribute, which is consistent with the previous article.
<?xml version="1.0" encoding="utf-8"?><resources> <attr name="borderRadius" format="dimension" /> <attr name="type"> <enum name="circle" value="0" /> <enum name="round" value="1" /> </attr> <declare-styleable name="RoundImageViewByXfermode"> <attr name="borderRadius" /> <attr name="type" /> </declare-styleable></resources>
2. Get attributes in the constructor
Public class RoundImageViewByXfermode extends ImageView {private Paint mPaint; private Xfermode mXfermode = new porterduxfermode (Mode. DST_IN); private Bitmap mMaskBitmap; private WeakReference <Bitmap> mWeakBitmap;/*** image type, circular or rounded corner */private int type; public static final int TYPE_CIRCLE = 0; public static final int TYPE_ROUND = 1;/*** default rounded corner size */private static final int BODER_RADIUS_DEFAULT = 10;/*** rounded corner size */private int mBorderRadius; public RoundImageViewByXfermode (Context context) {this (context, null); mPaint = new Paint (); mPaint. setAntiAlias (true);} public RoundImageViewByXfermode (Context context, AttributeSet attrs) {super (context, attrs); mPaint = new Paint (); mPaint. setAntiAlias (true); TypedArray a = context. obtainStyledAttributes (attrs, R. styleable. roundImageViewByXfermode); mBorderRadius =. getDimensionPixelSize (R. styleable. roundImageViewByXfermode_borderRadius, (int) TypedValue. applyDimension (TypedValue. COMPLEX_UNIT_DIP, BODER_RADIUS_DEFAULT, getResources (). getDisplayMetrics (); // The default value is 10dpLog. e ("TAG", mBorderRadius + ""); type =. getInt (R. styleable. roundImageViewByXfermode_type, TYPE_CIRCLE); // The default value is Circlea. recycle ();}
Get custom attributes and write some member variables ~~
3. onMeasure
@ Overrideprotected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super. onMeasure (widthMeasureSpec, heightMeasureSpec);/*** if the type is circular, the width and height of the view must be changed to be consistent. Take the small value as the standard */if (type = TYPE_CIRCLE) {int width = Math. min (getMeasuredWidth (), getMeasuredHeight (); setMeasuredDimension (width, width );}}
In onMeasure, if it is a circle, reset the view size.
4. onDraw
@ SuppressLint ("DrawAllocation") @ Overrideprotected void onDraw (Canvas canvas) {// retrieve bitmapBitmap bitmap = mWeakBitmap = null in the cache? Null: mWeakBitmap. get (); if (null = bitmap | bitmap. isRecycled () {// get DrawableDrawable drawable = getDrawable (); // get the width and height of drawable int dWidth = drawable. getIntrinsicWidth (); int dHeight = drawable. getIntrinsicHeight (); if (drawable! = Null) {// create bitmapbitmap = Bitmap. createBitmap (getWidth (), getHeight (), Config. ARGB_8888); float scale = 1.0f; // create a Canvas drawCanvas = new Canvas (bitmap); // calculate the zoom ratio based on the bitmap width and height and the view width and height; because the src width and height ratio may be different from the imageview width and height ratio, we do not want image distortion here; if (type = TYPE_ROUND) {// If the width or height of the image does not match the width and height of the view, calculate the scale to be scaled. The width and height of the scaled image are calculated, it must be larger than the width and height of our view. Therefore, we should take measures here; scale = Math. max (getWidth () * 1.0f/dWidth, getHeight () * 1.0f/dHeight);} els E {scale = getWidth () * 1.0F/Math. min (dWidth, dHeight);} // set bounds Based on the scaling ratio, which is equivalent to scaling the image by drawable. setBounds (0, 0, (int) (scale * dWidth), (int) (scale * dHeight); drawable. draw (drawCanvas); if (mMaskBitmap = null | mMaskBitmap. isRecycled () {mMaskBitmap = getBitmap ();} // Draw Bitmap. mPaint. reset (); mPaint. setFilterBitmap (false); mPaint. setXfermode (mXfermode); // draw the drawCanvas shape. drawBitmap (mMaskBitmap, 0, 0, m Paint); mPaint. setXfermode (null); // draws the prepared bitmap out of the canvas. drawBitmap (bitmap, 0, 0, null); // cache bitmap to avoid allocating mWeakBitmap = new WeakReference <Bitmap> (bitmap) Every time onDraw is called );}} // if bitmap still exists, you can directly draw if (bitmap! = Null) {mPaint. setXfermode (null); canvas. drawBitmap (bitmap, 0.0f, 0.0f, mPaint); return ;}/ *** draw shape * @ return */public Bitmap getBitmap () {Bitmap bitmap = Bitmap. createBitmap (getWidth (), getHeight (), Bitmap. config. ARGB_8888); Canvas canvas = new Canvas (bitmap); Paint paint = new Paint (Paint. ANTI_ALIAS_FLAG); paint. setColor (Color. BLACK); if (type = TYPE_ROUND) {canvas. drawRoundRect (new RectF (0, 0, getWidth (), getHeight (), mBorderRadius, mBorderRadius, paint);} else {canvas. drawCircle (getWidth ()/2, getWidth ()/2, getWidth ()/2, paint);} return bitmap ;}
Get drawable in onDraw, and then get the width and height of drawable. Perform proper scaling based on the current type and view width and height. Principles: refer to the scale Calculation of matrix in the previous article. The principles are the same.
Then configure the Xfermode. getBitmap will return the image based on the type and draw it directly to the bitmap in the memory. Finally, cache bitmap to avoid allocating memory and restarting the drawing each time onDraw.
You can extend the type, draw a heart shape, triangle or something, and add branches directly in getBitmap.
Finally, remember to do some processing in invalidate:
@Overridepublic void invalidate(){mWeakBitmap = null;if (mMaskBitmap != null){mMaskBitmap.recycle();mMaskBitmap = null;}super.invalidate();}
This is mainly because we cache the cache. When invalidate is called, the cache is cleared.
4. layout files and
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:zhy="http://schemas.android.com/apk/res/com.zhy.variousshapeimageview" android:layout_width="match_parent" android:layout_height="wrap_content" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.zhy.view.RoundImageViewByXfermode android:layout_width="130dp" android:layout_height="130dp" android:layout_margin="10dp" android:src="@drawable/qiqiu" > </com.zhy.view.RoundImageViewByXfermode> <com.zhy.view.RoundImageViewByXfermode android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:src="@drawable/aa" zhy:borderRadius="30dp" zhy:type="round" > </com.zhy.view.RoundImageViewByXfermode> <com.zhy.view.RoundImageViewByXfermode android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:src="@drawable/aa" zhy:type="circle" > </com.zhy.view.RoundImageViewByXfermode> <com.zhy.view.RoundImageViewByXfermode android:layout_width="40dp" android:layout_height="40dp" android:layout_margin="10dp" android:src="@drawable/aa" zhy:type="circle" > </com.zhy.view.RoundImageViewByXfermode> </LinearLayout></ScrollView>
:
Okay, it's relatively simple ~~
Declaration: This example referred to: https://github.com/MostafaGazar/CustomShapeImageView; but some of the Code has been changed, such as CustomShapeImageView if the image is a rectangle, but set to the circle type, the effect is still a rectangle; and directly compress bitmap and view ratios, similar to fitxy ~~~ These two points have been modified ~~ Of course, this case is more powerful than the function of this blog. You can also see the name, support many shapes, and support SVG ~ For your reference ~
Download source code
Bytes ----------------------------------------------------------------------------------------------------------
Some of the bloggers have already been online. If you do not like boring text, stamp it (for initial record, we look forward to your support ):
1. scratch cards for Android custom controls in e-commerce activities
2. Android custom controls create Android streaming layout and popular labels
3. Implementation of Android intelligent robot xiaomu
4. High imitation QQ5.0 slide
5. High imitation 5.2.1 main interface and message reminder