Source code and test examples have been put on GitHub Https://github.com/Leaking/SlideSwitch
As below, can not pass GIF pictures, temporarily cut a static picture. The color has a gradient effect when the button is sliding.
First of all, about the idea: The button draws three layers, the bottom is the gray covering the entire view, the second is a custom color covering the entire view, which can change the transparency. The third one is white. When the white part moves, modify the transparency of the second layer.
Probably record the implementation process of rewriting a component.
1, defining attributes
2, the constructor in Java code gets the value of the property
3, rewrite onmeasure ()
4, rewrite OnDraw ()
5, if necessary, rewrite Ontouch monitor
6, in the layout file of your project, define a namespace, use the properties
1, defining attributes
Create a new project, name Slieswitch, and create a new property file Slideswitch\res\values\attrs.xml
<?xml version= "1.0" encoding= "Utf-8"?><resources> <declare-styleable name= "Slideswitch" > <attr name= "themecolor" format= "color"/> <attr name= "IsOpen" format= "boolean"/> <attr Name= "Shape" > <enum name= "rect" value= "1"/> <enum name= "Circle" value= "2"/> </attr > </declare-styleable></resources>
It defines three properties, one is the color of the button, one is the open state of the button, one is the enumeration type, it is used to describe the shape of the button, about these properties and the use of several other types of properties, you can easily Baidu Google to the relevant knowledge, here is not a record.
2, the constructor in Java code gets the value of the property
Create a new package Com.leaking.slideswitch in Slieswitch, and then add a new file file Slieswitch.java in the package. The custom component first has to inherit the view class and then get the custom attributes in the constructor, as in the following Emma fragment:
public class Slideswitch extends View {//,,,,,,, omitted,,,,,,,,,, public Slideswitch (context context, AttributeSet attrs, int d EFSTYLEATTR) {Super (context, attrs, defstyleattr); listener = Null;paint = new Paint ();p Aint.setantialias (true); TypedArray a = context.obtainstyledattributes (attrs,r.styleable.slideswitch); color_theme = A.getcolor ( R.styleable.slideswitch_themecolor,color_theme); IsOpen = A.getboolean (R.styleable.slideswitch_isopen, false); Shape = A.getint (R.styleable.slideswitch_shape, Shape_rect); A.recycle ();} Public Slideswitch (context context, AttributeSet Attrs) {This (context, attrs, 0);} Public Slideswitch (Context context) {This (context, null);} ,,,,,,, Omit,,,,,,,,,,}
General view has three constructors, I used to let only one parameter of the construction method call has two parameters of the construction method, and then two calls three, in the construction method with three parameters using Typearray read the custom property, and then call Typearray's Recycle () method to reclaim resources.
3, rewrite onmeasure ()
Search the Internet a little bit, soon can only how to rewrite the Onmeasure () method, but why the need to rewrite the Onmeasure () method This point, it is not good to search. This question I recorded in another article.
Android Custom View-------why rewrite onmeasure () and how to rewrite
We have done two things here in Onmeasure (), the first is to calculate the size of the view, which is its length and width, the second is to record the starting position of the white color block, and some other parameters of the draw button. It is important to note that when you call the view's invalidate () method to redraw, the system only calls the OnDraw () method, but if there is a modification to the size and content of other components (such as the SetText () of TextView), Will trigger Onmeasure (), so the positional variables computed in onmeasure () are not affected by the recall of Onmeasure (). One of the bugs that the encoding process encounters is for this reason.
4, rewrite OnDraw ()
The OnDraw () section is relatively easy, just draw three layers according to the parameters calculated in Onmeasure ().
5, if necessary, rewrite Ontouch monitor
It is also easier to modify the transparency of the second layer's color by the Down,move,up three event calculation location, and then call Invaliate to redraw the view. Start a thread in the up event and let the button slide automatically to the end.
6, in the layout file of your project, define a namespace, using properties
<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http// Schemas.android.com/tools " xmlns:slideswitch=" Http://schemas.android.com/apk/res/com.example.testlibs " android:layout_width= "match_parent" android:layout_height= "match_parent" android:background= "# FFFFFFFF " android:gravity=" center_horizontal " android:orientation=" vertical " android:padding=" 10dip " tools:context=" com.example.testlibs.MainActivity "> <com.leaking.slideswitch.slideswitch android:id= "@+id/swit" android:layout_width= "150dip" android:layout_height= "60dip" Slideswitch:isopen= "true" slideswitch:shape= "rect" slideswitch:themecolor= "#ffee3a00" > </ Com.leaking.slideswitch.slideswitch></linearlayout>
It is important to note that the second line of the preceding code fragment introduces a namespace with the following format
xmlns: Random name = "Http://schemas.android.com/apk/res/the package name of your app"
Note that the last part is the app package name for the project that you use for this custom view.
Slideswitch.java Complete Code
Complete code and test examples are on GitHub, Https://github.com/Leaking/SlideSwitch.
Package Com.leaking.slideswitch;import Android.content.context;import Android.content.res.typedarray;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.Rect; Import Android.graphics.rectf;import android.os.handler;import Android.os.looper;import Android.os.Message;import Android.support.v4.view.motioneventcompat;import Android.util.attributeset;import android.view.MotionEvent; Import Android.view.view;import Com.example.slideswitch.r;public class Slideswitch extends View {public static final int Shape_rect = 1;public static final int shape_circle = 2;private static final int rim_size = 6;private static final int COL Or_theme = Color.parsecolor ("#ff00ee00");//3 Attributesprivate int color_theme;private boolean isopen;private int shape ;//Varials of drawingprivate Paint paint;private rect backrect;private rect frontrect;private int alpha;private int max_l eft;private int min_left;private int frontrect_left;private int Frontrect_left_begin = rim_size;private int eventstartx;private int eventlastx;private int DIFFX = 0;private SlideListener Listener ;p Ublic interface Slidelistener {public void open ();p ublic void Close ();} Public Slideswitch (context context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr); listener = Null;paint = new Paint ();p Aint.setantialias (true); TypedArray a = context.obtainstyledattributes (attrs,r.styleable.slideswitch); color_theme = A.getcolor ( R.styleable.slideswitch_themecolor,color_theme); IsOpen = A.getboolean (R.styleable.slideswitch_isopen, false); Shape = A.getint (R.styleable.slideswitch_shape, Shape_rect); A.recycle ();} Public Slideswitch (context context, AttributeSet Attrs) {This (context, attrs, 0);} Public Slideswitch (Context context) {This (context, null);}} @Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, HEIGHTMEASURESPEC); int width = measuredimension (280, widthmeasurespec); int height = MeasuredimEnsion (HEIGHTMEASURESPEC); if (shape = = shape_circle) {if (Width < height) width = height * 2;} Setmeasureddimension (width, height); Initdrawingval ();} public void Initdrawingval () {int width = getmeasuredwidth (); int height = getmeasuredheight (); backrect = new Rect (0, 0, wid th, height); min_left = rim_size;if (Shape = = shape_rect) Max_left = Width/2;elsemax_left = width-(height-2 * rim_size )-Rim_size;if (isOpen) {frontrect_left = Max_left;alpha = 255;} else {frontrect_left = Rim_size;alpha = 0;} Frontrect_left_begin = Frontrect_left;} public int measuredimension (int defaultsize, int measurespec) {int Result;int specmode = Measurespec.getmode (measureSpec int specsize = Measurespec.getsize (Measurespec), if (Specmode = = measurespec.exactly) {result = Specsize;} else {result = DefaultSize; Unspecifiedif (Specmode = = measurespec.at_most) {result = Math.min (result, specsize);}} return result;} @Overrideprotected void OnDraw (canvas canvas) {if (shape = = shape_rect) {Paint.setcolor (ColoR.gray); Canvas.drawrect (backrect, paint);p Aint.setcolor (color_theme);p Aint.setalpha (Alpha); Canvas.drawrect ( Backrect, paint); frontrect = new Rect (Frontrect_left, Rim_size, frontrect_left+ getmeasuredwidth ()/2-rim_size, GetMeas Uredheight ()-rim_size);p Aint.setcolor (Color.White); Canvas.drawrect (frontrect, paint);} else {//draw round int radius;radius = Backrect.height ()/2-rim_size;paint.setcolor (Color.gray); Canvas.drawroundrect (new RECTF (backrect), radius, radius, paint);p Aint.setcolor (color_theme);p Aint.setalpha (Alpha); Canvas.drawroundrect ( New RECTF (Backrect), radius, radius, paint) Frontrect = new Rect (Frontrect_left, Rim_size, frontrect_left+ Backrect.height ()-2 * rim_size, Backrect.height ()-rim_size);p Aint.setcolor (Color.White); Canvas.drawroundrect (new RECTF (frontrect), radius, radius, paint);}} @Overridepublic boolean ontouchevent (Motionevent event) {int action = motioneventcompat.getactionmasked (event); switch (action) {Case MotionEvent.ACTION_DOWN:eventStartX = (int) Event.getrawX (); Break;case MotionEvent.ACTION_MOVE:eventLastX = (int) event.getrawx ();d iffx = Eventlastx-eventstartx;int tempx = di FfX + frontrect_left_begin;tempx = (tempx > max_left? max_left:tempx); tempx = (Tempx < min_left? min_left:temp X); if (tempx >= min_left && tempx <= max_left) {frontrect_left = Tempx;alpha = (int) (255 * (float) tempx/ (float) max_left); Invalidateview ();} Break;case MotionEvent.ACTION_UP:int Wholex = (int) (EVENT.GETRAWX ()-eventstartx); frontrect_left_begin = Frontrect_ Left;boolean toright;toright = (Frontrect_left_begin > MAX_LEFT/2 true:false); if (Math.Abs (WholeX) < 3) {ToRig HT =!toright;} Movetodest (toright); break;default:break;} return true;} /** * Draw again */private void Invalidateview () {if (looper.getmainlooper () = = Looper.mylooper ()) {invalidate ();} else {P Ostinvalidate ();}} public void Setslidelistener (Slidelistener listener) {This.listener = listener;} public void Movetodest (final Boolean toright) {final Handler Handler =New Handler () {@Overridepublic void Handlemessage (Message msg) {if (msg.what = = 1) {Listener.open ();} else {Listener.close ();}}}; New Thread (New Runnable () {@Overridepublic void run () {if (toright) {while (Frontrect_left <= max_left) {alpha = (int) (255 * (float) frontrect_left/(float) max_left); Invalidateview (); Frontrect_left + = 3;try {thread.sleep (3);} catch (Inte Rruptedexception e) {e.printstacktrace ();}} Alpha = 255;frontrect_left = Max_left;isopen = true;if (listener! = null) handler.sendemptymessage (1); Frontrect_left_ begin = Max_left;} else {while (Frontrect_left >= min_left) {alpha = (int) (255 * (float) frontrect_left/(float) max_left); Invalidatevie W (); Frontrect_left-= 3;try {thread.sleep (3);} catch (Interruptedexception e) {e.printstacktrace ();}} Alpha = 0;frontrect_left = Min_left;isopen = false;if (listener! = null) handler.sendemptymessage (0); Frontrect_left_ begin = Min_left;}}). Start ();} public void SetState (Boolean isOpen) {This.isopen = Isopen;initdrawingval (); invalIdateview (); if (listener! = null) if (IsOpen = = True) {Listener.open ();} Else{listener.close ();}} public void Setshapetype (int shapetype) {this.shape = ShapeType;}}
Android Custom view-------Slide button