One: Introduction:
In the previous "Android using Bitmapshader Graphics rendering to achieve circular, rounded and elliptical custom picture view", using the Bitmapshader method to achieve custom round, fillet, and other custom ImageView, In this article we will use the more common Xfermode rendering scheme to achieve the imageview of circles, rounded corners and elliptical styles, and this example is also directly inherited ImageView,
This can save a lot of things, such as measurement steps, and do not need to write their own way to set up pictures, this article uses the dst_in mode in Xfermode mode to achieve the effect, of course, we can also use other models, such as src_in can achieve the effect.
(as usual complete source code at the end of the article to give the download address ha)
Two: Effect chart:
Three, Xfermode rendering mode introduction:
Xfermode affects how new colors are plotted on canvas already existing images
* Under normal circumstances, a new shape is drawn on the image, and if the new paint is not transparent, the color below will be obscured.
* If the new paint is transparent, it will be dyed to the following color
The following Xfermode subclasses can change this behavior:
AVOIDXFERMODE specifies a color and tolerance that forces the paint to avoid drawing on it (or drawing only on it).
Pixelxorxfermode a simple pixel XOR operation is applied when overwriting an existing color.
Porterduffxfermode This is a very powerful conversion mode, which allows you to use any of the 16 porter-duff rules of the image to control how paint interacts with existing canvas images.
Here we have to mention the classic diagram:
The above 16 modes are described as follows:
From the above we can see that Porterduff.mode is an enumeration class, with a total of 16 enumerated values:
1.porterduff.mode.clear
The drawing is not submitted to the canvas.
2.porterduff.mode.src
Show Upper Drawing Pictures
3.porterduff.mode.dst
Show lower drawing picture
4.porterduff.mode.src_over
The normal drawing display, the upper and lower layers draw the overlay.
5.porterduff.mode.dst_over
The upper and lower layers are displayed. The lower ranks show.
6.porterduff.mode.src_in
Draws the intersection of two layers. Displays the upper layer.
7.porterduff.mode.dst_in
Draws the intersection of two layers. Shows the lower level.
8.porterduff.mode.src_out
Draws a non-intersection portion of the upper layer.
9.porterduff.mode.dst_out
Remove the layer to draw the non intersection part.
10.porterduff.mode.src_atop
To remove the disjoint portion of a layer from the upper part
11.porterduff.mode.dst_atop
Take the upper part of the non-intersection and the lower intersection
12.porterduff.mode.xor
XOR: Removing the two Layer intersection section
13.porterduff.mode.darken
Take two layer all area, the intersection part color deepens
14.porterduff.mode.lighten
Take two layers all, light the intersection part of the color
15.porterduff.mode.multiply
Take two layer intersection part overlay color
16.porterduff.mode.screen
Take two layer all area, the intersection part becomes transparent color
The realization of the imageview of the custom circle, fillet and Ellipse
1, measuring the size of the view, the circle for special treatment
The code is as follows |
Copy Code |
/** * Measure the size of the view */ @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) { TODO auto-generated Method Stub Super.onmeasure (Widthmeasurespec, Heightmeasurespec); If the type is circular, force the view's width to be consistent, and take a smaller value with a wide height if (mtype = = type_circle) { int width = math.min (Getmeasuredwidth (), Getmeasuredheight ()); Setmeasureddimension (width, width); } } |
2, draw the bitmap of different graphics, for OnDraw () to draw the time with
The code is as follows |
Copy Code |
/**
* Draw different graphics bitmap
*/
Private Bitmap Getdrawbitmap () {
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 (mtype = = type_circle)
{//Draw Circle
Canvas.drawcircle (GetWidth ()/2, getwidth ()/2, getwidth ()/2,
Paint);
}else if (mtype = = Type_round)
{//Draw rounded Rectangle
Canvas.drawroundrect (New RECTF (0, 0, getwidth (), GetHeight ()),
Mroundborderradius, Mroundborderradius, paint);
}else if (mtype = = Type_oval) {
Draw Ellipse
Canvas.drawoval (New RECTF (0, 0, getwidth (), GetHeight ()), mpaint);
}
return bitmap;
} |
3, in the OnDraw () to draw out
The code is as follows |
Copy Code |
/**
* Draw the contents of the view
*/
@Override
protected void OnDraw (Canvas Canvas) {
TODO auto-generated Method Stub
Remove the bitmap from the cache
Bitmap bmp = (Mbufferbitmap = null null:mBufferBitmap.get ());
if (bmp = null | | bmp.isrecycled ()) {
If there is no cache presence
Get drawable
drawable drawable = getdrawable ();
Get the width and height of the drawable
int dwidth = Drawable.getintrinsicwidth ();
int dheight = Drawable.getintrinsicheight ();
LOG.V ("Czm", "dwidth=" +dwidth+ ", Width=" +getwidth ());
if (null!= drawable) {
BMP = Bitmap.createbitmap (GetWidth (), GetHeight (),
config.argb_8888);
float scale = 1.0f;
Create Canvas
Canvas Drawcanvas = new Canvas (BMP);
Calculates the scaling ratio according to the width of the bitmap and the height of the view; because the src width is set
The proportions may be different from the imageview ratio, where we don't want the picture to be distorted;
if (mtype = = type_circle)
{//If it's a circle
Scale = GetWidth () * 1.0f/math.min (Dwidth, dheight);
}else if (mtype = = Type_round | | mtype = = type_oval)
{//If a rounded rectangle or ellipse
If the width or height of the picture does not match the width of the view, calculate the proportion that needs to be scaled;
The height of the scaled picture must be greater than the width of our view; So here we take the big value;
Scale = Math.max (getwidth () * 1.0f/dwidth, GetHeight ()
* 1.0f/dheight);
}
LOG.V ("Czm", "scale=" +scale);
Depending on the scaling, set the bounds, which is equivalent to zooming the picture
Drawable.setbounds (0, 0, (int) (scale * dwidth), (int) (scale * dheight));
Drawable.draw (Drawcanvas);
Gets the bitmap, that is, the bitmap of a circle, fillet, or ellipse
if (Mmaskbitmap = null | | mmaskbitmap.isrecycled ()) {
Mmaskbitmap = Getdrawbitmap ();
}
Set Xfermode rendering mode for paint
Mpaint.reset ();
Mpaint.setfilterbitmap (FALSE);
Mpaint.setxfermode (Mxfermode);
Draw different shapes
Drawcanvas.drawbitmap (mmaskbitmap, 0, 0,mpaint);
Mpaint.setxfermode (NULL);
Draw the prepared bitmap.
Canvas.drawbitmap (BMP, 0, 0, NULL);
Bitmap cache to avoid allocating memory every time OnDraw is called
Mbufferbitmap = new weakreference<bitmap> (BMP);
}
}else{
If the cache still exists
Mpaint.setxfermode (NULL);
Canvas.drawbitmap (BMP, 0.0f, 0.0f, Mpaint);
Return
}
} |
4, because of the use of weak reference caching technology, you need to rewrite the invalidate () method to do some of the release of recycling resources, such as processing:
The code is as follows |
Copy Code |
/** * Because caching technology is used, it is necessary to do some recycling and release resources in invalidate */ @Override public void invalidate () { TODO auto-generated Method Stub Mbufferbitmap = null; if (Mmaskbitmap!= null) { Mmaskbitmap.recycle (); Mmaskbitmap = null; } Super.invalidate (); } |
Implementation of view layout:
The code is as follows |
Copy Code |
<scrollview xmlns:android= "Http://schemas.android.com/apk/res/android" Xmlns:tools= "Http://schemas.android.com/tools" Android:layout_width= "Match_parent" android:layout_height= "Match_parent" > <linearlayout android:layout_width= "match _parent android:layout_height= "wrap_content" android:gravity= "Center_horizontal" android:layout_margintop= "10DP" android:layout_marginbottom = "55DP" android:orientation= "vertical" <com.czm.myroundimageview.xcroundimageviewbyxfermode android:id= "@+id/cicleimageview" android:layout_width= "150DP" android:layout_height= "150DP" android:src= "@drawable/img1"/> <com.czm.myroundimageview.xcroundimageviewbyxfermode android:id= "@+id/roundrectimageview" android:layout_width= "125DP" android:layout_height= "145DP" android:layout_margintop= "15DP" android:src= "@drawable/img2"/> <com.czm.myroundimageview.xcroundimageviewbyxfermode Android:id= "@+id/ovalimageview" Android:layout_width= "140DP" android:layout_height= "184DP" android:layout_margintop= "15DP" android:src= "@drawable/img3"/> </LinearLayout> </ScrollView> |
Vi. using and Testing custom ImageView
The custom imageview that is drawn directly above is finished, the following is the use of this custom ImageView, using the same method as normal ImageView, as a normal control.
The code is as follows |
Copy Code |
Package Com.czm.myroundimageview; Import android.app.Activity; Import Android.os.Bundle; public class Mainactivity extends activity { Private Xcroundimageviewbyxfermode circleimageview;//Circular picture
Private Xcroundimageviewbyxfermode roundrectimageview;//rounded rectangular picture
Private Xcroundimageviewbyxfermode ovalimageview;//Oval picture
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
Initviews ();
}
/**
* Initialize views
*/
private void Initviews () {
Circleimageview = (xcroundimageviewbyxfermode) Findviewbyid (R.id.cicleimageview);
Roundrectimageview = (xcroundimageviewbyxfermode) Findviewbyid (R.id.roundrectimageview);
Ovalimageview = (xcroundimageviewbyxfermode) Findviewbyid (R.id.ovalimageview);
Roundrectimageview.settype (Xcroundimageviewbyxfermode.type_round);
Roundrectimageview.setroundborderradius (100);
Ovalimageview.settype (Xcroundimageviewbyxfermode.type_oval);
Ovalimageview.setroundborderradius (50);
} } |