自定義滑動開關
發表時(shí)間:2021-1-10
發布人(rén):融晨科技
浏覽次數:41
轉載請注明出(chū)處:http://blog.csdn.net/forwardyzk/article/details/42526343
當開發的(de)時(shí)候,使用開關的(de)時(shí)候,效果不(bù)能不(bù)滿足我們的(de)需求,要(yào / yāo)表現出(chū)滑動的(de)效果。我們就(jiù)可以(yǐ)自定義開關。
思路:
1.把開關分爲(wéi / wèi)兩部分,一部分是(shì)開關的(de)背景,另一部分是(shì)滑動按鈕。
2.測量開關的(de)長和(hé / huò)寬,當然是(shì)在(zài)onMeasure中進行處理
3.在(zài)onTouchEvent()根據觸摸開關進行滑動位置進行監聽,在(zài)onDraw()中進行繪畫。
當然也(yě)要(yào / yāo)繪畫兩部分:開關背景和(hé / huò)滑動按鈕
4.對觸摸位置和(hé / huò)滑動位置進行判斷
1.觸摸位置要(yào / yāo)在(zài)開關背景的(de)範圍内。
2.在(zài)繪畫的(de)時(shí)候,滑動按鈕不(bù)能超出(chū)開關背景的(de)範圍。
在(zài)onTouchEvent()方法中調用invalidate()方法,會根據位置的(de)變化不(bù)斷的(de)在(zài)onDraw()方法中繪畫按鈕。
設置開關的(de)背景和(hé / huò)滑動按鈕
onXPosition和(hé / huò)offXPosition爲(wéi / wèi)開關狀态的(de)變化之(zhī)間,滑動按鈕左側的(de)X坐标不(bù)能必須在(zài)兩者之(zhī)間。
public void setImageResource(int switchOnBg, int slipBtn) { Log.d(TAG, "setImageResource"); switch_bg = BitmapFactory.decodeResource(getResources(), switchOnBg); slip_Btn = BitmapFactory.decodeResource(getResources(), slipBtn); onXPosition = switch_bg.getWidth() - slip_Btn.getWidth(); offXPosition = 0; }
在(zài)OnTouchEvent()中監聽手勢滑動的(de)位置
public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { // 按下,判斷按下的(de)位置在(zài)開關上(shàng),才可以(yǐ)做後面的(de)操作 case MotionEvent.ACTION_DOWN: Log.d(TAG, "MotionEvent.ACTION_DOWN"); if (event.getX() > switch_bg.getWidth() || event.getY() > switch_bg.getHeight()) { return false; } isSlipping = true; currentX = event.getX(); break; // 滑動,記錄當前的(de)按下的(de)位置 case MotionEvent.ACTION_MOVE: Log.d(TAG, "MotionEvent.ACTION_MOVE"); currentX = event.getX(); break; // 松開,設置開關的(de)監聽器,設置開關的(de)狀态 case MotionEvent.ACTION_UP: Log.d(TAG, "MotionEvent.ACTION_UP"); isSlipping = false; // 松開前開關的(de)狀态 boolean previousSwitchState = isSwitchOn; // 如果當前的(de)位置在(zài)開關背景中間位置的(de)右側,表示的(de)是(shì)開的(de)狀态,否則爲(wéi / wèi)關 if (event.getX() >= (switch_bg.getWidth() / 2)) { isSwitchOn = true; } else { isSwitchOn = false; } // 如果設置了(le/liǎo)監聽器,則調用此方法 if (onSwitchListener != null && (previousSwitchState != isSwitchOn)) { onSwitchListener.onSwitched(isSwitchOn); } break; default: break; } // 重新繪制控件 invalidate();// 不(bù)要(yào / yāo)忘了(le/liǎo)重繪開關 return true; }
在(zài)最後不(bù)要(yào / yāo)忘了(le/liǎo)調用invalidate(),否則不(bù)會進行繪畫開關。
判斷了(le/liǎo)觸摸的(de)範圍必須在(zài)開關上(shàng)
在(zài)onDraw()繪畫開關
protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); Log.d(TAG, "onDraw"); Matrix matrix = new Matrix(); Paint paint = new Paint(); // 滑動按鈕的(de)X方向左側坐标 float left_SlipBtn; // 把開關的(de)背景畫出(chū)來(lái) canvas.drawBitmap(switch_bg, matrix, paint); // 判斷當前是(shì)否正在(zài)滑動 if (isSlipping) { if (currentX > switch_bg.getWidth()) { left_SlipBtn = switch_bg.getWidth() - slip_Btn.getWidth(); } else { // 保持滑動的(de)位置是(shì)滑動按鈕的(de)中間位置 left_SlipBtn = currentX - slip_Btn.getWidth() / 2; } } else { // 根據當前的(de)開關狀态設置滑動按鈕的(de)位置 if (isSwitchOn) { left_SlipBtn = onXPosition; } else { left_SlipBtn = offXPosition; } } // 對滑動按鈕左側和(hé / huò)右側進行判斷,不(bù)能超過背景的(de)範圍 if (left_SlipBtn < 0) { left_SlipBtn = 0; } else if (left_SlipBtn > switch_bg.getWidth() - slip_Btn.getWidth()) { left_SlipBtn = switch_bg.getWidth() - slip_Btn.getWidth(); } // 繪制滑動開關 canvas.drawBitmap(slip_Btn, left_SlipBtn, 0, paint); }
canvas.drawBitmap(switch_bg, matrix, paint)繪畫開關背景
canvas.drawBitmap(slip_Btn, left_SlipBtn, 0, paint)繪畫滑動按鈕
滑動按鈕滑動的(de)時(shí),保持不(bù)能超過開關背景的(de)範圍,保持點擊的(de)位置在(zài)滑動按鈕的(de)中間位置。
使用步驟:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/main_button_switch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="15dp" android:paddingBottom="3dp" android:paddingLeft="25dp" android:paddingRight="25dp" android:paddingTop="3dp" android:text="切換狀态" android:textSize="15sp" /> <com.example.view.MySlipSwitch android:id="@+id/main_myslipswitch" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="20dp" /> </RelativeLayout>
在(zài)MainActivity.java中使用
public class MainActivity extends Activity { private Button switch_Btn; private MySlipSwitch slipswitch_MSL; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); setListener(); } public void initView() { slipswitch_MSL = (MySlipSwitch) findViewById(R.id.main_myslipswitch); slipswitch_MSL.setImageResource(R.drawable.switch_bkg_switch, R.drawable.switch_btn_slip); slipswitch_MSL.setSwitchState(true); switch_Btn = (Button) findViewById(R.id.main_button_switch); } public void setListener() { //設置開關狀态變化監聽器 slipswitch_MSL.setOnSwitchListener(new OnSwitchListener() { @Override public void onSwitched(boolean isSwitchOn) { // TODO Auto-generated method stub if (isSwitchOn) { Toast.makeText(getApplicationContext(), "開關已經開啓", 0).show(); } else { Toast.makeText(getApplicationContext(), "開關已經關閉", 0).show(); } } }); switch_Btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { slipswitch_MSL.setSwitchState(!slipswitch_MSL.getSwitchState()); if (slipswitch_MSL.getSwitchState()) { Toast.makeText(getApplicationContext(), "開關已經開啓", 0).show(); } else { Toast.makeText(getApplicationContext(), "開關已經關閉", 0).show(); } } }); } }
點擊切換按鈕,獲取開關的(de)狀态
設置滑動開關狀态的(de)的(de)監聽器,滑動的(de)位置影響到(dào)了(le/liǎo)開關的(de)狀态,有響應的(de)監聽。
源碼下載: http://download.csdn.net/detail/forwardyzk/8341363
效果圖:
[img]http://img.blog.csdn.net/20150108165542997?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZm9yd2FyZHl6aw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center