Android自定義控件仿iOS滑塊SwitchButton
SwitchButton可以點(diǎn)擊的時候切換狀態(tài),類似CheckBox
在拖動的時候,也可以根據(jù)拖動的距離判斷是否切換狀態(tài),類似ToggleButton
因此要區(qū)別出單擊事件和拖動事件
實現(xiàn)效果如圖所示:

自定義的SwitchButton如下:
public class SwitchButton extends View implements View.OnTouchListener {
private Bitmap bg_on, bg_off, slipper_btn;
/**
* 按下時的x和當(dāng)前的x
*/
private float downX, nowX;
/**
* 記錄用戶是否在滑動
*/
private boolean onSlip = false;
/**
* 當(dāng)前的狀態(tài)
*/
private boolean nowStatus = false;
/**
* 監(jiān)聽接口
*/
private OnChangedListener listener;
/**
* 一個滑動的距離臨界值,判斷是滑動還是點(diǎn)擊
* getScaledTouchSlop():
* Distance in pixels a touch can wander before we think the user is scrolling
* */
private int mTouchSlop=new ViewConfiguration().getScaledTouchSlop();
public SwitchButton(Context context) {
super(context);
init();
}
public SwitchButton(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void init(){
//載入圖片資源
bg_on = BitmapFactory.decodeResource(getResources(), R.mipmap.switch_on_on);
bg_off = BitmapFactory.decodeResource(getResources(), R.mipmap.switch_off_off);
slipper_btn = BitmapFactory.decodeResource(getResources(), R.mipmap.switch_ball_ball);
setOnTouchListener(this);
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Matrix matrix = new Matrix();
Paint paint = new Paint();
float x = 0;
//根據(jù)nowX設(shè)置背景,開或者關(guān)狀態(tài)
if (nowX < (bg_on.getWidth()/2)){
canvas.drawBitmap(bg_off, matrix, paint);//畫出關(guān)閉時的背景
}else{
canvas.drawBitmap(bg_on, matrix, paint);//畫出打開時的背景
}
if (onSlip) {//是否是在滑動狀態(tài),
if(nowX >= bg_on.getWidth())//是否劃出指定范圍,不能讓滑塊跑到外頭,必須做這個判斷
x = bg_on.getWidth() - slipper_btn.getWidth()/2;//減去滑塊1/2的長度
else
x = nowX - slipper_btn.getWidth()/2;
}else {
if(nowStatus){//根據(jù)當(dāng)前的狀態(tài)設(shè)置滑塊的x值
x = bg_on.getWidth() - slipper_btn.getWidth();
}else{
x = 0;
}
}
//對滑塊滑動進(jìn)行異常處理,不能讓滑塊出界
if (x < 0 ){
x = 0;
}
else if(x > bg_on.getWidth() - slipper_btn.getWidth()){
x = bg_on.getWidth() - slipper_btn.getWidth();
}
//畫出滑塊
canvas.drawBitmap(slipper_btn, x, 0, paint);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:{
if (event.getX() > bg_off.getWidth() || event.getY() > bg_off.getHeight()){
return false;
}else{
onSlip = true;
downX = event.getX();
nowX = downX;
}
break;
}
case MotionEvent.ACTION_MOVE:{
nowX = event.getX();
break;
}
case MotionEvent.ACTION_UP:{
DebugLog.e("mTouchSlop:"+mTouchSlop);
onSlip = false;
nowX = event.getX();
float float_distance=nowX - downX;
int int_disatnce=(int)float_distance;
DebugLog.e("int_disatnce:"+int_disatnce);
/**
* 滑動距離太短,認(rèn)定是點(diǎn)擊事件
*/
if(Math.abs(int_disatnce)<mTouchSlop){
if(this.isChecked()){
this.setChecked(false);
nowX = 0;
}else{
this.setChecked(true);
nowX = bg_on.getWidth() - slipper_btn.getWidth();
}
}else{
/**
* 滑動距離足夠,認(rèn)為是滑動事件
*/
if(event.getX() >= (bg_on.getWidth()/2)){
nowStatus = true;
nowX = bg_on.getWidth() - slipper_btn.getWidth();
}else{
nowStatus = false;
nowX = 0;
}
}
if(listener != null){
listener.OnChanged(SwitchButton.this, nowStatus);
}
break;
}
}
//刷新界面
invalidate();
return true;
}
/**
* 為WiperSwitch設(shè)置一個監(jiān)聽,供外部調(diào)用的方法
* @param listener
*/
public void setOnChangedListener(OnChangedListener listener){
this.listener = listener;
}
/**
* 設(shè)置滑動開關(guān)的初始狀態(tài),供外部調(diào)用
* @param checked
*/
public void setChecked(boolean checked){
if(checked){
nowX = bg_off.getWidth();
}else{
nowX = 0;
}
nowStatus = checked;
}
public boolean isChecked() {
return nowStatus;
}
/**
* 回調(diào)接口
*
*/
public interface OnChangedListener {
public void OnChanged(SwitchButton wiperSwitch, boolean checkState);
}
}
布局文件中使用:
<com.uestcneon.chuji.changjianglife.share.SwitchButton android:id="@+id/user_privacy_state" android:layout_width="wrap_content" android:layout_height="20dp" android:layout_marginLeft="30dp" />
控件用到的3個資源圖片:



以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中通過ActionBar為標(biāo)題欄添加搜索及分享視窗
這篇文章主要介紹了ANDROID中通過ACTIONBAR為標(biāo)題欄添加搜索以及分享視窗的相關(guān)資料,需要的朋友可以參考下2016-12-12
Android ViewPager實現(xiàn)Banner循環(huán)播放
這篇文章主要為大家詳細(xì)介紹了Android ViewPager實現(xiàn)Banner循環(huán)播放,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09
Android四大組件之BroadcastReceiver詳解
今天小編就為大家分享一篇關(guān)于Android四大組件之BroadcastReceiver詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01
Android ListView 單條刷新方法實踐及原理解析
這篇文章主要介紹了Android ListView 單條刷新方法實踐及原理解析的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-07-07
詳解Android中通過Intent類實現(xiàn)組件間調(diào)用的方法
Intent能夠?qū)崿F(xiàn)應(yīng)用間的數(shù)據(jù)交互與通訊,將實現(xiàn)者和調(diào)用者解耦,接下來就來詳解Android中通過Intent類實現(xiàn)組件間調(diào)用的方法,需要的朋友可以參考下2016-05-05
Android基于opencv實現(xiàn)多通道分離與合并
針對圖像多通道的分離與混合,OpenCV 4中提供了split()函數(shù)和merge()函數(shù)用于解決這些需求。本文講解一下Android如何調(diào)用這些函數(shù)實現(xiàn)多通道分離與合并2021-06-06
ubuntu下 AndroidStudio4.1啟動報錯問題的解決
這篇文章主要介紹了ubuntu下 AndroidStudio4.1啟動報錯問題的解決,本文給大家分享個人經(jīng)驗對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
Android拖拽助手ViewDragHelper的創(chuàng)建與使用實例
ViewDragHelper是針對 ViewGroup 中的拖拽和重新定位 views 操作時提供了一系列非常有用的方法和狀態(tài)追蹤,下面這篇文章主要給大家介紹了關(guān)于Android拖拽助手ViewDragHelper的創(chuàng)建與使用的相關(guān)資料,需要的朋友可以參考下2022-05-05

