The effect is as follows:
A brief introduction to Bitmapshader
About Shader
What is, what Shader
kinds of types and how to use does not belong to the scope of this article, on this aspect is not very understanding of the students, suggested that first to learn Shader
the basic use.
BitmapShader
The main function is through the paint object, the canvas for the specified Bitmap
fill, to achieve a series of effects, you can have the following three modes to choose
1. CLAMP
-Stretching, here is the last element of the picture, repeated repeatedly, this effect, in the picture is relatively small, and the area to be painted larger time will be more obvious.
2. REPEAT
-Repeat, horizontal longitudinal repeated, different from the previous mode, this model in the picture is relatively small can not meet the requirements are, will be in the horizontal portrait of the repeated drawing of graphics.
3. MIRROR
-Flip, this pattern REPEAT
is similar to the one, except that the repetition here is the flip of repetition, and the effect of origami is almost the same.
And we're going to use the CLAMP
pattern, because as long as we control the size of the graphic, we can avoid stretching the image.
Introduction to specific implementation
To customize the image, border width and color, first in the Res/values directory, create a new Attrs.xml file, which will be written below
<?xml version= "1.0" encoding= "Utf-8"?>
<resources>
<declare-styleable name= "Mycustomview" >
<attr name= "mborder_color" format= "color" ></attr> <attr name= "mborder_width" format= "
Dimension "></attr>
<attr name=" MSRC "format=" reference "></attr>
</ Declare-styleable>
</resources>
Of course, there are a few other features you can add here. Now that we have defined the attributes we want to use, we need to View
parse them and take advantage of them in our customizations, and the parsing process looks like this
TypedArray type = Context.obtainstyledattributes (Attrs, r.styleable.mycustomview);
Mbordercolor = Type.getcolor (r.styleable.mycustomview_mborder_color,0);
mdrawable = type.getdrawable (R.STYLEABLE.MYCUSTOMVIEW_MSRC);
Convert the obtained drawable into Bitmap
bitmapdrawable bitmapdrawable = (bitmapdrawable) mdrawable;
Mbitmap = Bitmapdrawable.getbitmap ();
Mborderwidth = Type.getdimensionpixelsize (R.styleable.mycustomview_mborder_width, 2);
It is worth noting that the mSrc
parsing of attributes, because the acquisition is an Drawable
object, we need to convert it to an Bitmap
object.
The following is the use of the object we obtained for the Bitmap
drawing of the circular head, BitmapShader
and Paint
the initialization of the following is as follows
Msrcbitmap = Bitmap.createscaledbitmap (Mbitmap, Mwidth, Mheight, false);
Mshader = new Bitmapshader (Msrcbitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Mpaint = new Paint ();
Mpaint.setshader (Mshader);
Mradius = (Mwidth-mborderwidth * 2-4)/2;
Mcirclex = (mwidth)/2;
Mcircley = (mheight)/2;
Msrcbitmap is the image obtained by the appropriate reduction or amplification to adapt to our graphics requirements, mWidth
and here and what is it? mHeight
It's actually the values that we're passing in and out of the definition view layout_width
layout_height
, but I've dealt with them here, which is to select the minimum operation, so that you can avoid the phenomenon that the image fills up with the specified area because it is wide or tall. It is noteworthy that the custom view requires wrap_content
special handling, otherwise the system will not display the view of the property. As for how to handle, you can look at this example of the source code, very simple, I believe a lot of people know or say early on the chest.
One more thing to emphasize here is the radius of the mRadius
circle that will be drawn, why subtract the width of the border by 2? You know, our circle is drawn according to the width or height specified by the view, and if the circle we are drawing is exactly the incircle of the specified view, where is the border? It's definitely going to be drawn outside the view so that we don't see the full border. So, the point of subtracting is to make room for the border.
After the above, we have already drawn the circle head, the following to draw a border, but it is very simple, I just define an Paint
object, and use it to draw a circle, the brush's initialization operation is as follows
Mborderpaint = new Paint ();
Mborderpaint.setstyle (Paint.Style.STROKE);
Mborderpaint.setstrokewidth (mborderwidth);
Mborderpaint.setcolor (Mbordercolor);
Mborderpaint.setstrokecap (Paint.Cap.ROUND);
Well, here's what you can onDraw()
do in the function, as shown below
@Override
protected void OnDraw (Canvas Canvas) {
super.ondraw (Canvas);
Canvas.drawcircle (Mcirclex, Mcircley, Mradius, mpaint);
Canvas.drawcircle (Mcirclex, Mcircley, Mradius, mborderpaint);
In this way, the entire effect is completed. Let's take a look at how to use
<com.example.hwaphon.patheffecttest.myview
android:layout_width= "wrap_content"
android:layout_ height= "Wrap_content"
android:layout_marginbottom= "16DP"
android:layout_marginright= "8DP"
app: Mborder_color= "@android: Color/holo_green_light"
app:mborder_width= "4DP"
app:msrc= "@drawable/myview_ Test "/>
Note that you must add a phrase to the container
Xmlns:app=http://schemas.android.com/apk/res-auto
The core code of the concrete implementation
Package com.example.hwaphon.patheffecttest;
Import Android.content.Context;
Import Android.content.res.TypedArray;
Import Android.graphics.Bitmap;
Import Android.graphics.BitmapShader;
Import Android.graphics.Canvas;
Import Android.graphics.Paint;
Import Android.graphics.Shader;
Import android.graphics.drawable.BitmapDrawable;
Import android.graphics.drawable.Drawable;
Import Android.util.AttributeSet;
Import Android.view.View;
/** * Created by Hwaphon on 2016/5/12.
* * public class MyView extends View {private Bitmap mbitmap;
Private drawable mdrawable;
Private Bitmap Msrcbitmap;
Private Bitmapshader Mshader;
Private Paint Mpaint;
private int mwidth, mheight;
private int Mradius;
private int Mcirclex, Mcircley;
private int mbordercolor;
Private Paint Mborderpaint;
private int mborderwidth;
Public MyView {This (context, NULL);
Public MyView (context, AttributeSet attrs) {Super (context, attrs); TypedArray type = Context.obtainstYledattributes (Attrs, R.styleable.mycustomview);
Mbordercolor = Type.getcolor (r.styleable.mycustomview_mborder_color,0);
mdrawable = type.getdrawable (R.STYLEABLE.MYCUSTOMVIEW_MSRC);
Convert the obtained drawable into Bitmap bitmapdrawable bitmapdrawable = (bitmapdrawable) mdrawable;
Mbitmap = Bitmapdrawable.getbitmap ();
Mborderwidth = Type.getdimensionpixelsize (R.styleable.mycustomview_mborder_width, 2); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec,
HEIGHTMEASURESPEC);
Mwidth = Measurewidth (Widthmeasurespec);
Mheight = Measureheight (Heightmeasurespec); int temp = mwidth > mheight?
Mheight:mwidth;
Mwidth = Mheight = temp;
Initview ();
Setmeasureddimension (Mwidth, mheight);
private int measureheight (int heightmeasurespec) {int size = Measurespec.getsize (HEIGHTMEASURESPEC);
int sizeMode = Measurespec.getmode (Heightmeasurespec);
int result = 0;
if (SizeMode = = measurespec.exactly) { result = size;
else {result = 200;
if (SizeMode = = measurespec.at_most) {result = Math.min (result, size);
} return result;
private int measurewidth (int widthmeasurespec) {int size = Measurespec.getsize (WIDTHMEASURESPEC);
int sizeMode = Measurespec.getmode (Widthmeasurespec);
int result = 0;
if (SizeMode = = measurespec.exactly) {result = size;
else {result = 200;
if (SizeMode = = measurespec.at_most) {result = Math.min (result, size);
} return result;
} private void Initview () {msrcbitmap = Bitmap.createscaledbitmap (Mbitmap, Mwidth, Mheight, false);
Mshader = new Bitmapshader (Msrcbitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Mpaint = new Paint ();
Mpaint.setshader (Mshader);
Mradius = (Mwidth-mborderwidth * 2)/2;
Mcirclex = (mwidth)/2;
Mcircley = (mheight)/2;
Mborderpaint = new Paint ();
Mborderpaint.setstyle (Paint.Style.STROKE);
Mborderpaint.setstrokewidth (Mborderwidth); MbordeRpaint.setcolor (Mbordercolor);
Mborderpaint.setstrokejoin (Paint.Join.ROUND);
Mborderpaint.setstrokecap (Paint.Cap.ROUND);
} @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
Canvas.drawcircle (Mcirclex, Mcircley, Mradius, Mpaint);
Canvas.drawcircle (Mcirclex, Mcircley, Mradius, Mborderpaint); }
}
Summarize
That's what Android uses Bitmapshader to make all the stuff that comes with a rounded head, and hopefully this article will help you when you're developing Android, and if you have questions, you can talk.