Custom view has always been a hurdle for Android developers.
The relationship between view and ViewGroup
From view and ViewGroup relationship, ViewGroup inherits view.
View subclasses, mostly functional controls, provide the style to draw, such as Imageview,textview, and ViewGroup subclasses, used to manage the size of controls, locations, such as Linearlayout,relativelayout, As you can see from the figure below,
From the practical application, they are also the combination of relations, we are in the layout, often a viewgroup nested multiple viewgroup or view, and nested viewgroup will nest multiple viewgroup or view
As follows
Second, the view of the drawing process
From view Source view, the main relationship three methods:
1, Measure (): Measurement
A final method that controls the size of the control
2, Layout (): Layout
To control the location of your layout
Have relativity, only relative to their own parent-class layout, do not care about ancestral layout
3, Draw (): Drawing
Used to control the display style of a control
Process: process measure--> layout--> Draw
The method that corresponds to our implementation is
Onmeasure ()
OnLayout ()
OnDraw ()
In actual drawing, our thinking order is generally like this:
Whether you want to control the size of the control--> is-->onmeasure ()
(1) If this custom view is not a viewgroup,onmeasure () method call Setmeasuredeminsion (width,height): Used to set its own size
(2) if the Viewgroup,onmeasure () method is invoked, child.measure () measures the child's size, gives the child's expected size value, and then-->setmeasuredeminsion (width,height): Use to set your own size
Whether you want to control the placement of controls--> is-->onlayout ()
Do you want to control the appearance of the control--> is the drawing of-->ondraw ()-->canvas
Here's the flowchart I'm drawing:
The following is an example of a custom slide button to illustrate the drawing process of a custom view
We look forward to achieving this effect:
Drag or click on the button, the switch to the right slide, into
The switch can slide to the corresponding position with the touch of the finger until it is finally fixed on the switch position.
Create a new class that inherits from view and implements its two constructed methods
public class Switchbuttonview extends View {public
Switchbuttonview (context
, null);
Public
Switchbuttonview (context, AttributeSet attrs) {
Super (context, attrs);
Add these two pictures to the drawable resource
In this case, we can use Onmeasure () to determine the size of this control
@Override
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
Mswitchbutton = Bitmapfactory.decoderesource (Getresources (), r.drawable.switch_background);
Mslidebutton = Bitmapfactory.decoderesource (Getresources (), r.drawable.slide_button_background);
Setmeasureddimension (Mswitchbutton.getwidth (), Mswitchbutton.getheight ());
}
This control does not need to control its placement, skip onlayout ();
Next OnDraw () determines its shape.
But we need to determine the shape based on the different behaviors we click on the control, which requires rewriting the ontouchevent ()
The logic is:
When pressed, triggers the event motionevent.action_down, if the state is off at this time:
(1) If the finger touch point (through Event.getx () to the right of the center line of the button, the button to the right to slide a distance (Event.getx () and the switch control width of the difference, specific look at the source below)
(2) If the finger touch point on the left side of the button centerline, the button is still at the leftmost (that is, "off" state).
If the state is open at this time:
(1) If the finger touch point on the left side of the button centerline, the button to the left to slide a distance
(2) If the finger touch point on the right side of the button centerline, the button is still at the far right (that is, "open" state)
When sliding, the trigger time is motionevent.action_move, and the logic is consistent with the press
Note that ontouchevent () requires that the return value be set to True, otherwise the slide event cannot be responded to
When the finger is closed, if the switch centerline is located on the left side of the entire control centerline, the setting state is off, otherwise, set to open.
The specific source code is as follows: (also provides an external exposure at this time the switch state of the interface)
Customizing the View section
Package Com.lian.switchtogglebutton;
Import Android.content.Context;
Import Android.graphics.Bitmap;
Import Android.graphics.BitmapFactory;
Import Android.graphics.Canvas;
Import Android.graphics.Paint;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import android.view.MotionEvent;
Import Android.view.View;
/** * Created by Lian on 2016/3/20. * * public class Switchbuttonview extends View {private static final int state_null = 0;//default state private static fin
Al int state_down = 1;
private static final int state_move = 2;
private static final int state_up = 3;
Private Bitmap Mslidebutton;
Private Bitmap Mswitchbutton;
Private Paint Mpaint = new Paint ();
private int buttonstate = State_null;
private float mdistance;
Private Boolean isopened = false;
Private Onswitchlistener Mlistener;
Public Switchbuttonview {This (context, NULL); Public Switchbuttonview, AttributeSet attrs) {Super (context, attrs); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {Mswitchbutton = Bitmapf
Actory.decoderesource (Getresources (), r.drawable.switch_background);
Mslidebutton = Bitmapfactory.decoderesource (Getresources (), r.drawable.slide_button_background);
Setmeasureddimension (Mswitchbutton.getwidth (), Mswitchbutton.getheight ());
} @Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
if (mswitchbutton!= null) {Canvas.drawbitmap (Mswitchbutton, 0, 0, mpaint);
The value of//buttonstate determines the switch (buttonstate) {case State_down:case state_move in Ontouchevent ():
if (!isopened) {Float middle = mslidebutton.getwidth ()/2f;
if (Mdistance > middle) {Float max = Mswitchbutton.getwidth ()-mslidebutton.getwidth ();
float left = Mdistance-middle;
if (left >= max) {left = max;
} canvas.drawbitmap (Mslidebutton,left,0,mpaint);
else {canvas.drawbitmap (mslidebutton,0,0,mpaint);
}else{Float middle = mswitchbutton.getwidth ()-mslidebutton.getwidth ()/2f;
if (Mdistance < middle) {float left = mdistance-mslidebutton.getwidth ()/2f;
float min = 0;
if (left < 0) {left = min;
} canvas.drawbitmap (Mslidebutton,left,0,mpaint);
}else{Canvas.drawbitmap (Mslidebutton,mswitchbutton.getwidth ()-mslidebutton.getwidth (), 0,mPaint);
}} break;
Case State_null:case State_up:if (isopened) {log.d ("switch", "open");
Canvas.drawbitmap (Mslidebutton,mswitchbutton.getwidth ()-mslidebutton.getwidth (), 0,mpaint);
}else{log.d ("switch", "closed"); Canvas.drawbitmaP (mslidebutton,0,0,mpaint);
} break;
Default:break; @Override public boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case
MotionEvent.ACTION_DOWN:mDistance = Event.getx ();
LOG.D ("Down", "press");
ButtonState = State_down;
Invalidate ();
Break
Case MotionEvent.ACTION_MOVE:buttonState = State_move;
Mdistance = Event.getx ();
LOG.D ("Move", "moving");
Invalidate ();
Break
Case MotionEvent.ACTION_UP:mDistance = Event.getx ();
ButtonState = state_up;
LOG.D ("Up", "off");
if (mdistance >= mswitchbutton.getwidth ()/2f) {isopened = true;
}else {isopened = false;
} if (Mlistener!= null) {mlistener.onswitchchanged (isopened);
} invalidate ();
Break
Default:break; return true;
public void Setonswitchlistener (Onswitchlistener listener) {This.mlistener = listener;
public interface onswitchlistener{void Onswitchchanged (Boolean isopened); }
}
Demoactivity:
Package Com.lian.switchtogglebutton;
Import Android.os.Bundle;
Import android.support.v7.app.AppCompatActivity;
Import Android.widget.Toast;
public class Mainactivity extends Appcompatactivity {
@Override
protected void OnCreate (Bundle Savedinstancestate) {
super.oncreate (savedinstancestate);
Setcontentview (r.layout.activity_main);
Switchbuttonview Switchbuttonview = (switchbuttonview) Findviewbyid (R.id.switchbutton);
Switchbuttonview.setonswitchlistener (New Switchbuttonview.onswitchlistener () {
@Override public
Void Onswitchchanged (Boolean isopened) {
if (isopened) {
toast.maketext (mainactivity.this, "open", toast.length_ Short). Show ();
else {
Toast.maketext (mainactivity.this, "close", Toast.length_short). Show ();}}}
Layout:
<?xml version= "1.0" encoding= "Utf-8"?> <relativelayout 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"
android:paddingbottom= "@dimen/activity_ Vertical_margin "
android:paddingleft=" @dimen/activity_horizontal_margin "
android:paddingright=" @dimen Activity_horizontal_margin "
android:paddingtop=" @dimen/activity_vertical_margin "
tools:context=" Com.lian.switchtogglebutton.MainActivity ">
<com.lian.switchtogglebutton.switchbuttonview
Android:id= "@+id/switchbutton"
android:layout_width= "wrap_content"
android:layout_height= "WRAP_" Content "
/>
The above is the entire content of this article, I hope to help you learn.