Androidbitmapshader Real-round, rounded picture
Reprint please indicate the source: http://blog.csdn.net/lmj623565791/article/details/41967509, this article from: "Zhang Hongyang Blog" 1, overview
Remember beginners that would have written a blog Android perfect to achieve the picture fillet and Circle (analysis of the implementation), mainly a custom view plus the use of xfermode implementation. In fact, to achieve a rounded picture of the method should be a lot, common is the use of xfermode,shader. This blog will directly inherit directly inherit ImageView, using Bitmapshader to achieve the drawing of rounded corners, if you are able to read, I guess what shape can be drawn out.
2.
This is a demo diagram of the Fillet ~ ~ This is nothing to say, directly set the size of the fillet on the line;
This is a circular display diagram, which needs to be noted here, because the picture set may be a rectangle, for example: There are two rectangles, a wide larger, a higher than the larger;
So we want to show it as a circle, and we're probably going to zoom in or zoom out (because the width of the image may not fit the length of the set, and we need to zoom in on it).
This one picture, the middle is the normal size, the upper and lower respectively is the big extra small, mainly can when the size is bigger than or is smaller than the setting size, we need to enlarge or reduce it;
Fillet when the picture and the width of the view is not consistent, also need to zoom out, here is not, code inside to see it.
3, talking about Bitmapshader
Bitmapshader is a subclass of Shader that can be set by Paint.setshader (Shader Shader),
Here we only focus on Bitmapshader, the construction method:
Mbitmapshader = new Bitmapshader (bitmap, Tilemode.clamp, Tilemode.clamp);
Parameter 1:bitmap
Parameter 2, parameter 3:tilemode;
There are three types of Tilemode:
CLAMP stretching
REPEAT Repeat
MIRROR Mirroring
If you set the screen screensaver, if the picture is too small, you can choose to repeat, stretch, mirror;
repeat: this bitmap is repeated horizontally and vertically.
Mirror: The cross is constantly flipping and repeating;
Stretch: This and the computer screensaver should be a little different, this stretch is the last pixel of the picture, the last horizontal row of pixels, continuous repetition, the column of the vertical line of pixels, constantly repeating;
Now you probably understand, bitmapshader by setting it to Mpaint, and then drawing with this mpaint, the drawing area is colored according to the tilemode you set.
One thing to note here is that Bitmapshader is drawn from the upper-left corner of your canvas and does not draw a square in the lower-right corner of the view, and it does not start in the upper-left corner of your square.
Well, to this, I believe that you have a certain understanding of bitmapshader, of course, if you want to fully understand shader, please refer to the god of Love: custom control is actually very simple 1/3 .
For our rounded corners and circles, we set the pattern to be clamp, but will you have a question:
is the width or height of the view wider or taller than our bitmap stretched?
Well, we're going to set up a matrix for bitmapshader, to zoom in or out of the image properly, not to allow "view width or height in our bitmap wide or high" condition.
The basic introduction of our principle is complete, get drawable converted to bitmap, and then directly initialize Bitmapshader, brush set shader, finally in the OnDraw inside to draw a circle on the line.
4, Bitmapshader actual combat
First, look at the rounded or rounded corners that are implemented using Bitmapshader.
We directly inherit the ImageView here, so that you can set the image of the code will be more familiar with, but we need to support two modes, then we need to customize the properties:
1. Custom Attributes
Values/attr.xml
<?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= "Roundimageview" > <attr name= "Borderradius"/> <attr name= "type"/> </declare-styleable></resources>
We define an enumeration and a fillet size of Borderradius.
2. Getting Custom properties
public class Roundimageview extends imageview{/** * Picture type, round or rounded */private int type;private static final int type_circle = 0;private static final int type_round = 1;/** * Fillet size default value */private static final int boder_radius_default = 10;/** * Fillet size */private int mborderradius;/** * Drawing of paint */private paint mbitmappaint;/** * Fillet radius */private int mradius;/** * 3x3 Matrix, Main Used to zoom out */private Matrix mmatrix;/** * Rendered image, use image coloring for drawing graphics */private bitmapshader mbitmapshader;/** * View width */private int MW Idth;private RECTF mroundrect;public Roundimageview (context context, AttributeSet Attrs) {Super (context, attrs); Mmatrix = new Matrix (); mbitmappaint = new Paint (); Mbitmappaint.setantialias (true); TypedArray a = context.obtainstyledattributes (Attrs,r.styleable.roundimageview); Mborderradius = A.getdimensionpixelsize (R.styleable.roundimageview_borderradius, (int) typedvalue.applydimension ( Typedvalue.complex_unit_dip,boder_radius_default, Getresources (). Getdisplaymetrics ()));//default = 10dptype = A.getInt ( R.styleable.rOundimageview_type, type_circle);//default is Circlea.recycle ();}
You can see some of our member variables, which are basically annotated, and then we get our custom properties in the constructor and the initialization of some variables.
3, Onmeasure
@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {log.e ("TAG", "onmeasure"); Super.onmeasure (Widthmeasurespec, heightmeasurespec);/** * If the type is circular, force the width of the view to be the same, with a small value of quasi-*/if (type = = Type_circle) { Mwidth = Math.min (Getmeasuredwidth (), Getmeasuredheight ()), Mradius = Mwidth/2;setmeasureddimension (MWidth, mWidth);}}
We've made a copy of the Onmeasure method, which is mainly used when the setting type is round, we force the view to be the same width and height.
Next only set Bitmapshader and draw the
4. Set Bitmapshader
/** * Initialize bitmapshader */private void Setupshader () {drawable drawable = getdrawable (); if (drawable = = null) {return;} Bitmap bmp = Drawabletobitamp (drawable);//BMP as a shader, which is drawn in the specified area Bmpmbitmapshader = new Bitmapshader (BMP, Tilemode.clamp , tilemode.clamp); float scale = 1.0f;if (type = = type_circle) {//Get bitmap wide or high decimal value int bsize = Math.min (Bmp.getwidth (), bmp.ge Theight ()); scale = Mwidth * 1.0f/bsize;} else if (type = = Type_round) {//If the width or height of the picture does not match the width and height of the view, the scale that needs to be scaled is calculated; The width of the scaled image must be greater than the width of our view; so we take a large value here; scale = Math.max ( GetWidth () * 1.0f/bmp.getwidth (), getheight () * 1.0f/bmp.getheight ()); Shader transformation matrix, we are mainly used to enlarge or reduce the Mmatrix.setscale (scale),//Set the transformation matrix Mbitmapshader.setlocalmatrix (Mmatrix);// Set Shadermbitmappaint.setshader (Mbitmapshader);}
In the Setupshader, the first transformation of drawable into our bitmap;
Then initialize Mbitmapshader = new Bitmapshader (BMP, Tilemode.clamp, Tilemode.clamp);
Next, scale is calculated based on the type and the width of the bitmap and view;
About the calculation of scale:
Round: Take the bitmap wide or high small value as the benchmark, if the large value, the scale will certainly not fill our circular area. Then, the view of the mwidth/bsize; The scale is what we get.
Fillet: Because the design to the width/height ratio, we respectively getwidth () * 1.0f/bmp.getwidth () and GetHeight () * 1.0f/bmp.getheight (), the final value, because we want to finish the final zoom picture must be greater than I The area of the view, somewhat similar to centercrop;
For example: the width of the view is 10*20, the width of the picture is 5*100, and finally we should enlarge it according to the width, rather than the ratio of the height, because we need to make the scaled image more custom than our view width and guarantee the original proportions.
With scale, it can be set to our matrix;
Then use Mbitmapshader.setlocalmatrix (Mmatrix);
Finally, set the Bitmapshader to paint.
Code about drawable to bitmap:
/** * drawable Turn Bitmap * * @param drawable * @return */private Bitmap drawabletobitamp (drawable drawable) {if (drawable instanceof bitmapdrawable) {bitmapdrawable BD = (bitmapdrawable) Drawable;return bd.getbitmap ();} int w = drawable.getintrinsicwidth (); int h = drawable.getintrinsicheight (); Bitmap Bitmap = Bitmap.createbitmap (W, H, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas (bitmap);d rawable.setbounds (0, 0, W, h);d Rawable.draw (canvas); return bitmap;}
Finally we will call Setupshader () in the OnDraw and then draw.
5. Drawing
Here, the last step is drawn, because our scope, and the scale are all done, so really only left to draw.
@Overrideprotected void OnDraw (canvas canvas) {if (getdrawable () = = null) {return;} Setupshader (); if (type = = Type_round) {canvas.drawroundrect (Mroundrect, Mborderradius, mborderradius,mbitmappaint);} Else{canvas.drawcircle (Mradius, Mradius, Mradius, mbitmappaint);//drawsomething (canvas);}} @Overrideprotected void onsizechanged (int w, int h, int oldw, int oldh) {super.onsizechanged (W, H, OLDW, OLDH);//Fillet picture Range if (type = = type_round) Mroundrect = new RECTF (0, 0, getwidth (), getheight ());}
Drawing is very simple, draw a circle, rounded rectangle and so on. The bounds of the rounded rectangle mroundrect initialized within the onsizechanged.
5, the state of the storage and recovery of course, if the memory is not enough, but just our activity in the background, unfortunately restarted, or the user rotated the screen caused the activity to restart, our view should also be able to save its own properties as far as possible. What is the use of State preservation? For example, now a fillet size is 10DP, the user clicks to become 50DP, when the user rotates, or after a long time in the background, return to our activity should be 50dp; we simply store the current type and Mborderradius
private static final String state_instance = "State_instance";p rivate static final String state_type = "State_type";p Rivat E static final String State_border_radius = "State_border_radius"; @Overrideprotected parcelable onsaveinstancestate () { Bundle bundle = new bundle (); Bundle.putparcelable (State_instance, Super.onsaveinstancestate ()); Bundle.putint (State_ type, type); Bundle.putint (State_border_radius, Mborderradius); return bundle;} @Overrideprotected void Onrestoreinstancestate (parcelable state) {if (state instanceof bundle) {Bundle bundle = (bundle) State;super.onrestoreinstancestate ((Bundle) state). Getparcelable (State_instance)); This.type = Bundle.getint ( State_type); This.mborderradius = Bundle.getint (State_border_radius);} Else{super.onrestoreinstancestate (state);}}
The code is relatively simple. Our article in the demo, the first, the fourth is clickable, after the click will change, you can click and then rotate the screen to test.
We also announced two methods for dynamically modifying the fillet size and type
public void Setborderradius (int borderradius) {int pxval = dp2px (Borderradius); if (This.mborderradius! = pxval) { This.mborderradius = Pxval;invalidate ();}} public void SetType (int type) {if (This.type! = type) {This.type = Type;if (this.type! = Type_round && This.type! =) type_circle) {this.type = type_circle;} Requestlayout ();}} public int dp2px (int dpval) {return (int) typedvalue.applydimension (Typedvalue.complex_unit_dip,dpval, Getresources () . Getdisplaymetrics ());}
Finally, post our layout files and mainactivity.
6. Call the layout file:
<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.vi ew. Roundimageview android:id= "@+id/id_qiqiu" android:layout_width= "Wrap_content" Android:lay out_height= "Wrap_content" android:layout_margin= "10DP" android:src= "@drawable/qiqiu" > < ;/com.zhy.view.roundimageview> <com.zhy.view.roundimageview android:layout_width= "200DP" android:layout_height= "200DP" android:layout_margin= "10DP" android:src= "@drawable/aa" > </com.zhy.view.RoundImageView> <coM.zhy.view.roundimageview android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Android:layout_margin= "10DP" android:src= "@drawable/icon" > </com.zhy.view.roundimagevie w> <com.zhy.view.roundimageview android:id= "@+id/id_meinv" android:layout_width= "Wrap_c Ontent "android:layout_height=" wrap_content "android:layout_margin=" 10DP "android:src=" @d Rawable/aa "zhy:borderradius=" 20DP "zhy:type=" Round "> </com.zhy.view.roundimageview> ; <com.zhy.view.roundimageview android:layout_width= "wrap_content" android:layout_height= "Wrap_cont Ent "android:layout_margin=" 10DP "android:src=" @drawable/icon "zhy:borderradius=" 40DP " Zhy:type= "Round" > </com.zhy.view.RoundImageView> <com.zhy.view.roundimageview Android:layoUt_width= "Wrap_content" android:layout_height= "wrap_content" android:layout_margin= "10DP" android:src= "@drawable/qiqiu" zhy:borderradius= "60DP" zhy:type= "Round" > </com.zhy.vie W.roundimageview> </LinearLayout></ScrollView>
No, scrollview inside a linear layout, inside a pile of roundimageview.
Mainactivity
Package Com.zhy.variousshapeimageview;import Android.app.activity;import Android.os.bundle;import Android.view.view;import Android.view.view.onclicklistener;import Com.zhy.view.roundimageview;public Class Mainactivity extends Activity{private roundimageview mqiqiu;private roundimageview mmeinv; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main); Mqiqiu = (Roundimageview) Findviewbyid (R.id.id_qiqiu); MMEINV = (Roundimageview) Findviewbyid (R.ID.ID_MEINV); Mqiqiu.setonclicklistener (New Onclicklistener () {@Overridepublic void OnClick (View v) {Mqiqiu.settype ( Roundimageview.type_round);}); Mmeinv.setonclicklistener (New Onclicklistener () {@Overridepublic void OnClick (View v) {Mmeinv.setborderradius (90);}});}}
Well, this blog is over. You can try to draw a Pentagon or God horse shape, or add a frame of God horse, believe that their own changes should be no problem ~ ~ Code may exist bugs and shortcomings, welcome your point, common progress.
The final:
SOURCE Click to download
----------------------------------------------------------------------------------------------------------
Bo Master part of the video has been online, if you do not like boring text, please poke (first record, look forward to your support):
1. Android custom control Scratch card in real-action e-commerce activities
2. Android custom controls build Android streaming layouts and popular tags
3. android Robot "Little Mu" implementation
4, High imitation QQ5.0 slide
5, High imitation 5.2.1 main interface and message alert
Original link This article by Bean John Blog Backup expert remote One click release
Androidbitmapshader Real-round, rounded corners picture (reprint)