Basic tutorial for Android -- 8.3.6 Paint API -- Xfermode and PorterDuff (3)
This section introduces:
In the previous section, we learned the three sons in Xfermode: porterduxfermode, which is a parameter in the constructor:
PorterDuff. ModeAfter viewing 16 image mixing modes, we wrote code to verify
There are 18 different mixed-layout modes, and 18 are added with the ADD and OVERLAY modes! Of course, verification alone is not enough,
This section describes how to use PorterDuff. Mode to provide
These mixed sorting modes! The example in this section is: Implementation of circular & rounded corner graphics!
In the Basic tutorial of Android-2.3.4 ImageView (Image view), we finally explained the simplest
The implementation of drawing a circular ImageView is to call clipPath on the image to cut out a circular image!
This section usesPorterDuff. ModeInDST_INMode to achieve, not to mention, start the content of this section!
PS: In this example, we use the Android Xfermode to create a circular and rounded image.
In addition, you still need to paste PorterDuff. Mode:
1. Implementation and implementation process analysis:
After running:
Well, the above is an effect we want to achieve.PorterDuff. Mode. DST_INMode!
Let's analyze and analyze the implementation process:
Step 1:
Xfermode is composed of two layers of graphs. It is called the DST graph (the target graph) and the SRC graph (the source image ).
Circle or rounded corner. We can first draw the image to be displayed (DST). Here we set it through the src attribute;
Then draw the circle and the rounded corner (SRC). The part we want to display is the place where they intersect and the content of the image part,
So select:
DST_INMode!
Step 2:
Well, now that we know the principle, we need to consider the problems related to custom ImageView:
If we want to draw a View that is rounded or circular, we need to add an attribute to judge, and the rounded corner also needs a rounded corner radius.
Parameters, so we can use the custom attributes (attrs. xml) method, and then in the Custom View constructor
Obtain these parameters! The calculation of the image size is as follows:
FirstIf we set a circle, we need to make the width and height consistent. Take the minimum value as the standard. We can use the onMesure () method
Call getMeasuredXxx () to obtain the width and height. If the value is smaller, call setMeasuredDimension (x, x). Set the width and height!
ThenIn the onDraw () method, we obtain the image width and height, and then calculate the zoom ratio based on the image width and height and View width and height,
The width and height of the fake image do not match the width and height of the View. The width and height of the picture must be greater than that of the View!
ThenDefine a method for drawing the image, initialize the paint brush, and set setXfermode
PorterDuff. Mode. DST_IN, draw the image first, and then draw the image
LastIt is something of the image cache. Here WeakReference is used to cache the image to avoid Memory Allocation every time onDraw
And redraw, and finally clear the cache in invalidate!
The general implementation process is shown above. It is much easier to know the process and then look at the code!
2. Code implementation:
Custom control attributes:Res/attrs. xml:
The following is the custom ImageView:CircleImageView. java:
/*** Created by Jay on 0025. */public class CircleImageView extends ImageView {private Paint mPaint; private Xfermode mXfermode = new porterduxfermode (PorterDuff. mode. DST_IN); private Bitmap mMaskBitmap; private WeakReference
MWeakBitmap; // image-related attributes private int type; // type, circular or rounded corner public static final int TYPE_CIRCLE = 0; public static final int TYPE_ROUND = 1; private static final int BODER_RADIUS_DEFAULT = 10; // default rounded corner size value private int mBorderRadius; // rounded corner size public CircleImageView (Context context) {this (context, null );} public CircleImageView (Context context, AttributeSet attrs) {super (context, attrs); mPaint = new Paint (); MPaint. setAntiAlias (true); // retrieves the TypedArray tArray = context value we set for the View in attrs. obtainStyledAttributes (attrs, R. styleable. circleImageView); mBorderRadius = tArray. getDimensionPixelSize (R. styleable. circleImageView_Radius, BODER_RADIUS_DEFAULT); type = tArray. getInt (R. styleable. circleImageView_type, TYPE_CIRCLE); tArray. recycle ();} public CircleImageView (Context context, AttributeSet attrs, int def StyleAttr) {super (context, attrs, defStyleAttr) ;}@ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {super. onMeasure (widthMeasureSpec, heightMeasureSpec); if (type = TYPE_CIRCLE) {int width = Math. min (getMeasuredWidth (), getMeasuredHeight (); setMeasuredDimension (width, width); // set the size of the current View }}@ Override protected void onDraw (Canvas canvas) {// retrieve bitmap Bitm from the cache Ap bitmap = mWeakBitmap = null? Null: mWeakBitmap. get (); if (bitmap = null | bitmap. isRecycled () {// obtain the image width and height Drawable drawable = getDrawable (); int width = drawable. getIntrinsicWidth (); int height = drawable. getIntrinsicHeight (); if (drawable! = Null) {bitmap = Bitmap. createBitmap (getWidth (), getHeight (), Bitmap. config. ARGB_8888); Canvas drawCanvas = new Canvas (bitmap); float scale = 1.0f; if (type = TYPE_ROUND) {scale = Math. max (getWidth () * 1.0f/width, getHeight () * 1.0f/height);} else {scale = getWidth () * 1.0F/Math. min (width, height);} // set bounds Based on the scaling ratio, which is equivalent to zooming the drawable image. setBounds (0, 0, (int) (scale * width), (int) (scale * height); drawable. draw (drawCanvas); if (mMaskBitmap = null | mMaskBitmap. isRecycled () {mMaskBitmap = getBitmap ();} mPaint. reset (); mPaint. setFilterBitmap (false); mPaint. setXfermode (mXfermode); // draw the drawCanvas shape. drawBitmap (mMaskBitmap, 0, 0, mPaint); // cache bitmap to avoid allocating mWeakBitmap = new WeakReference every time onDraw is called.
(Bitmap); // draw the image canvas. drawBitmap (bitmap, 0, 0, null); mPaint. setXfermode (null) ;}} if (bitmap! = Null) {mPaint. setXfermode (null); canvas. drawBitmap (bitmap, 0.0f, 0.0f, mPaint); return ;}// cache Bitmap to avoid allocating memory and drawing every OnDraw @ Override public void invalidate () {mWeakBitmap = null; if (mWeakBitmap! = Null) {mMaskBitmap. recycle (); mMaskBitmap = null;} super. invalidate () ;}// defines a method for drawing shapes. private 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); // anti-sawtooth 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 ;}}