Android custom SwitchButton switch control, android Custom button

Source: Internet
Author: User

Android custom SwitchButton switch control, android Custom button

SwitchButton controls have become very popular. There are a variety of styles. The SwitchButton control is generally used for app software settings to control cache, sound, prompt, download, and so on. Is a good UI experience and user habits. Next we will introduce a SwitchButton switch control. Add the source code.

Download source code: Click

I. view the implemented


Ii. Custom SwitchButton

This is a SwitchButton class that inherits the CheckBox. First, prepare the images and draw the border, background, and buttons of the control on canvas. Add the corresponding image when you draw the image. Then, use the onTouchEvent function to accept the effect after pressing, sliding, and releasing. Then it will probably come out. Next, let's look at the specific code.

Package com.org. switchbtn; import com. switchbutton. activity. r; import android. content. context; import android. content. res. resources; import android. graphics. bitmap; import android. graphics. bitmapFactory; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. graphics. porterDuff; import android. graphics. porterduxfermode; import android. graphics. rectF; impo Rt android. util. attributeSet; import android. view. motionEvent; import android. view. viewConfiguration; import android. view. viewParent; import android. widget. checkBox; public class SwitchButton extends CheckBox {private Paint mPaint; private ViewParent mParent; private Bitmap mBottom; private Bitmap mCurBtnPic; private Bitmap mBtnPressed; private Bitmap mBtnNormal; private Bitmap mFrame; private Bitmap MMask; private RectF mSaveLayerRectF; private porterduxfermode mXfermode; private float mFirstDownY; // Y private float mFirstDownX pressed for the first time; // X private float mRealPos pressed for the first time; // The Position of the image to be drawn is private float mBtnPos; // The Position of the button is private float mBtnOnPos; // the position of the switch is private float mBtnOffPos; // the position of the switch is private float mMaskWidth; private float mMaskHeight; private float mBtnWidth; private float mBtnInitPos; priva Te int mClickTimeout; private int mTouchSlop; private final int MAX_ALPHA = 255; private int mAlpha = MAX_ALPHA; private boolean mChecked = false; private boolean mBroadcasting; private boolean mTurningOn; private comment mclick mPerformClick; private OnCheckedChangeListener mOnCheckedChangeListener; private OnCheckedChangeListener mOnCheckedChangeWidgetListener; private boolean mAnimating; private Final float VELOCITY = 350; private float mVelocity; private final float EXTENDED_OFFSET_Y = 15; private float mExtendOffsetY; // expand the area in the Y axis to private float mAnimationPosition; private float location; public SwitchButton (Context context, AttributeSet attrs) {this (context, attrs, android. r. attr. checkboxStyle);} public SwitchButton (Context context) {this (context, null);} public Swit ChButton (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle); initView (context);} private void initView (Context context) {mPaint = new Paint (); mPaint. setColor (Color. WHITE); Resources resources = context. getResources (); // get viewConfiguration mClickTimeout = ViewConfiguration. getPressedStateDuration () + ViewConfiguration. getTapTimeout (); mTouchSlop = ViewConfig Uration. get (context ). getScaledTouchSlop (); // get Bitmap mBottom = BitmapFactory. decodeResource (resources, R. drawable. bottom); mBtnPressed = BitmapFactory. decodeResource (resources, R. drawable. btn_pressed); mBtnNormal = BitmapFactory. decodeResource (resources, R. drawable. btn_unpressed); mFrame = BitmapFactory. decodeResource (resources, R. drawable. frame); mMask = BitmapFactory. decodeResource (resources, R. drawable. mask); mCurBtnPic = mBtnNormal; mBtnWidth = mBtnPressed. getWidth (); mMaskWidth = mMask. getWidth (); mMaskHeight = mMask. getHeight (); mBtnOffPos = mBtnWidth/2; mBtnOnPos = mMaskWidth-mBtnWidth/2; mBtnPos = mChecked? MBtnOnPos: mBtnOffPos; mRealPos = getRealPos (mBtnPos); final float density = getResources (). getDisplayMetrics (). density; mVelocity = (int) (VELOCITY * density + 0.5f); mExtendOffsetY = (int) (density * density + 0.5f); priority = new RectF (0, mExtendOffsetY, mMask. getWidth (), mMask. getHeight () + mExtendOffsetY); mXfermode = new porterduxfermode (PorterDuff. mode. SRC_IN) ;}@ Overr Ide public void setEnabled (boolean enabled) {mAlpha = enabled? MAX_ALPHA: MAX_ALPHA/2; super. setEnabled (enabled);} public boolean isChecked () {return mChecked;} public void toggle () {setChecked (! MChecked);}/*** call this method internally to set the checked status. This method delays the execution of various callback functions, ensure smoothness of the animation ** @ param checked */private void setCheckedDelayed (final boolean checked) {this. postDelayed (new Runnable () {@ Override public void run () {setChecked (checked) ;}, 10 );} /*** <p> * Changes the checked state of this button. * </p> ** @ param checked true to check the button, false to uncheck it */public void setChecked (boolean chec Ked) {if (mChecked! = Checked) {mChecked = checked; mBtnPos = checked? MBtnOnPos: mBtnOffPos; mRealPos = getRealPos (mBtnPos); invalidate (); // Avoid infinite recursions if setChecked () is called from a // listener if (mBroadcasting) {return ;} mBroadcasting = true; if (mOnCheckedChangeListener! = Null) {mOnCheckedChangeListener. onCheckedChanged (SwitchButton. this, mChecked);} if (mOnCheckedChangeWidgetListener! = Null) {mOnCheckedChangeWidgetListener. onCheckedChanged (SwitchButton. this, mChecked);} mBroadcasting = false;}/*** Register a callback to be invoked when the checked state of this button * changes. ** @ param listener the callback to call on checked state change */public void setOnCheckedChangeListener (OnCheckedChangeListener listener) {mOnCheckedChangeListener = listener;}/*** Registe R a callback to be invoked when the checked state of this button * changes. this callback is used for internal purpose only. ** @ param listener the callback to call on checked state change * @ hide */void listener (OnCheckedChangeListener listener) {mOnCheckedChangeWidgetListener = listener;} @ Override public boolean onTouchEvent (MotionEvent event) {int action = event. ge TAction (); float x = event. getX (); float y = event. getY (); float deltaX = Math. abs (x-mFirstDownX); float deltaY = Math. abs (y-mFirstDownY); switch (action) {case MotionEvent. ACTION_DOWN: attemptClaimDrag (); mFirstDownX = x; mFirstDownY = y; mCurBtnPic = mBtnPressed; mBtnInitPos = mChecked? MBtnOnPos: mBtnOffPos; break; case MotionEvent. ACTION_MOVE: float time = event. getEventTime ()-event. getDownTime (); mBtnPos = mBtnInitPos + event. getX ()-mFirstDownX; if (mBtnPos> = mBtnOffPos) {mBtnPos = mBtnOffPos;} if (mBtnPos <= mBtnOnPos) {mBtnPos = mBtnOnPos ;} mTurningOn = mBtnPos> (mBtnOffPos-mBtnOnPos)/2 + mBtnOnPos; mRealPos = getRealPos (mBtnPos); break; case MotionEvent. ACTIO N_UP: mCurBtnPic = mBtnNormal; time = event. getEventTime ()-event. getDownTime (); if (deltaY <mTouchSlop & deltaX <mTouchSlop & time <mClickTimeout) {if (mPerformClick = null) {mPerformClick = new multiple mclick ();} if (! Post (mPerformClick) {initialize mclick () ;}} else {startAnimation (! MTurningOn);} break;} invalidate (); return isEnabled ();} private final class implements mclick implements Runnable {public void run () {extends mclick ();}} @ Override public boolean initialize mclick () {startAnimation (! MChecked); return true;}/*** Tries to claim the user's drag motion, and requests disallowing any * ancestors from stealing events in the drag. */private void attemptClaimDrag () {mParent = getParent (); if (mParent! = Null) {mParent. requestDisallowInterceptTouchEvent (true) ;}/ *** convert btnPos to RealPos ** @ param btnPos * @ return */private float getRealPos (float btnPos) {return btnPos-mBtnWidth/2;} @ Override protected void onDraw (Canvas canvas) {canvas. saveLayerAlpha (mSaveLayerRectF, mAlpha, Canvas. MATRIX_SAVE_FLAG | Canvas. CLIP_SAVE_FLAG | Canvas. HAS_ALPHA_LAYER_SAVE_FLAG | Canvas. FULL_COLOR_LAYER_SAV E_FLAG | Canvas. CLIP_TO_LAYER_SAVE_FLAG); // draw the canvas. drawBitmap (mMask, 0, mExtendOffsetY, mPaint); mPaint. setXfermode (mXfermode); // draw the canvas of the bottom image. drawBitmap (mBottom, mRealPos, mExtendOffsetY, mPaint); mPaint. setXfermode (null); // draw the border canvas. drawBitmap (mFrame, 0, mExtendOffsetY, mPaint); // draw the canvas button. drawBitmap (mCurBtnPic, mRealPos, mExtendOffsetY, mPaint); canvas. restore () ;}@ Override pro Tected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {trim (int) mMaskWidth, (int) (mMaskHeight + 2 * mExtendOffsetY);} private void startAnimation (boolean turnOn) {mAnimating = true; mAnimatedVelocity = turnOn? -MVelocity: mVelocity; mAnimationPosition = mBtnPos; new SwitchAnimation (). run ();} private void stopAnimation () {mAnimating = false;} private final class SwitchAnimation implements Runnable {@ Override public void run () {if (! MAnimating) {return;} doAnimation (); FrameAnimationController. requestAnimationFrame (this) ;}} private void doAnimation () {mAnimationPosition + = mAnimatedVelocity * FrameAnimationController. increment/1000; if (mAnimationPosition <= mBtnOnPos) {stopAnimation (); mAnimationPosition = mBtnOnPos; increment (true);} else if (mAnimationPosition> = mBtnOffPos) {stopAnimation (); mAnimationPosition = mBtnOffPos; setCheckedDelayed (false);} moveView (mAnimationPosition);} private void moveView (float position) {mBtnPos = position; mRealPos = getRealPos (mBtnPos ); invalidate ();}}

Ii. control auxiliary class FrameAnimationController

package com.org.switchbtn;import android.os.Handler;import android.os.Message;public class FrameAnimationController {private static final int MSG_ANIMATE = 1000;public static final int ANIMATION_FRAME_DURATION = 1000 / 60;private static final Handler mHandler = new AnimationHandler();private FrameAnimationController() {throw new UnsupportedOperationException();}public static void requestAnimationFrame(Runnable runnable) {Message message = new Message();message.what = MSG_ANIMATE;message.obj = runnable;mHandler.sendMessageDelayed(message, ANIMATION_FRAME_DURATION);}public static void requestFrameDelay(Runnable runnable, long delay) {Message message = new Message();message.what = MSG_ANIMATE;message.obj = runnable;mHandler.sendMessageDelayed(message, delay);}private static class AnimationHandler extends Handler {public void handleMessage(Message m) {switch (m.what) {case MSG_ANIMATE:if (m.obj != null) {((Runnable) m.obj).run();}break;}}}}
3. Check the last listener, call, and implement MainActivity

Because the custom SwitchButton class inherits the checkbox. Therefore, OnCheckedChangeListener is used. Use this interface to implement listening.

Package com. switchbutton. activity; import com.org. switchbtn. switchButton; import android. OS. bundle; import android. app. activity; import android. widget. compoundButton; import android. widget. compoundButton. onCheckedChangeListener; import android. widget. toast; public class MainActivity extends Activity implements OnCheckedChangeListener {private SwitchButton mmsgpolicyswitch; private SwitchButton mMsgSoundSwitch; @ Overrideprotected void onCreate (Bundle savedInstanceState. onCreate (savedInstanceState); setContentView (R. layout. activity_main); initUI ();} private void initUI () {mmsgpolicyswitch = (SwitchButton) findViewById (R. id. message_policy_switch); mMsgSoundSwitch = (SwitchButton) findViewById (R. id. message_sound_switch); mmsgpolicyswitch. setOnCheckedChangeListener (this); mMsgSoundSwitch. setOnCheckedChangeListener (this) ;}@ Overridepublic void onCheckedChanged (CompoundButton buttonView, boolean isChecked) {switch (buttonView. getId () {case R. id. message_policy_switch: if (isChecked) {Toast. makeText (this, "New message reminder opens", Toast. LENGTH_SHORT ). show ();} else {Toast. makeText (this, "New message reminder disabled", Toast. LENGTH_SHORT ). show ();} break; case R. id. message_sound_switch: if (isChecked) {Toast. makeText (this, "enable voice notification", Toast. LENGTH_SHORT ). show ();} else {Toast. makeText (this, "sound reminder disabled", Toast. LENGTH_SHORT ). show () ;}break; default: break ;}}}
4. Attach the final xml

<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">    <RelativeLayout        android:id="@+id/sound_and_vibrate"        android:layout_width="fill_parent"        android:layout_height="44.0dip"        android:background="@drawable/common_strip_setting_bottom"        android:clickable="false"        android:focusable="false" >        <TextView            style="@style/B4_Font_white"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:layout_marginLeft="12.0dip"            android:duplicateParentState="true"            android:gravity="center_vertical"            android:text="@string/set_message_sound" />        <com.org.switchbtn.SwitchButton            android:id="@+id/message_sound_switch"            android:layout_width="80dip"            android:layout_height="28dip"            android:layout_alignParentRight="true"            android:layout_centerVertical="true"            android:layout_marginRight="8.0dip" />    </RelativeLayout>    <RelativeLayout        android:id="@+id/pushSetting"        android:layout_width="fill_parent"        android:layout_height="44.0dip"        android:layout_alignParentLeft="true"        android:layout_below="@+id/sound_and_vibrate"        android:background="@drawable/common_strip_setting_top"        android:clickable="false"        android:focusable="false" >        <TextView            android:id="@+id/encoding_style"            style="@style/B4_Font_white"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerVertical="true"            android:layout_marginLeft="12.0dip"            android:duplicateParentState="true"            android:gravity="center_vertical"            android:text="@string/set_message_notify" />        <com.org.switchbtn.SwitchButton            android:id="@+id/message_notify_switch"            android:layout_width="80dip"            android:layout_height="28dip"            android:layout_alignParentRight="true"            android:layout_centerVertical="true"            android:layout_marginRight="8.0dip" />    </RelativeLayout></RelativeLayout>
This is the end. Welcome to learn about custom controls.

Download source code: Click

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.