1. 程式人生 > >SwitchButton 開關按鈕 的多種實現方式 (附原始碼DEMO)

SwitchButton 開關按鈕 的多種實現方式 (附原始碼DEMO)

剛開始接觸開關樣式的按鈕是在iOS系統上面,它的切換以及滑動十分帥氣,深入人心。

所謂的開關按鈕,就是隻有2個狀態:on和off,下圖就是系統IOS 7上開關按鈕效果。

起初我在Android上我只會使用CheckBox去滿足對應的功能。後來,檢視開發文件發現,android也有了自己的原生態開關控制元件,並且在4.0版本中又優化加入了新的類似控制元件--Switch控制元件,以及使用起來十分簡單的ToggleButton,可是它們只是帶有切換效果,而不帶有滑動切換效果,並且Switch控制元件只支援高版本的系統,對於2.3就不支援。所以,要想看如何實現滑動切換的效果,必須瞭解這些控制元件的實現方式。下面,讓我們檢視下android開發文件,看看這些是如何實現使用的。

注意:本文中涉及到自定義控制元件 並自定義配置屬性declare-styleable,

檢視檢視開發文件:

CompoundButton

以上4類都是開關型別切換的控制元件,它們的父類都是CompoundButton。

 它對應的方法和類有:

點選選擇監聽介面。

Nested Classes

interface

Interface definition for a callback to be invoked when the checked state of a compound button changed.

返回左右填充的VIEW,加上間隔


Public Methods

int

()Returns the left padding of the view, plus space for the left Drawable if any.

int

()Returns the right padding of the view, plus space for the right Drawable if any.

boolean:是否被選中。

設定Button的Drawable屬性

void

(int resid)Set the background to a given Drawable, identified by its resource id.

設定是否選中

void

(boolean checked)Changes the checked state of this button.

改變當前的狀態,true-->false  ;false-->true

void

()Change the checked state of the view to the inverse of its current state

控制元件全域性 繪製

void

( canvas)Implement this to do your drawing.

protected void onDraw (Canvas canvas)

實現你自己的繪製。

引數

                            canvas    在畫布上繪製背景

protected boolean verifyDrawable (Drawable who)

如果你的檢視子類顯示他自己的視覺化物件,他將要重寫此方法並且為了顯示可繪製返回true。此操作允許進行繪製時有動畫效果。

  確認當重寫從方法時,需呼叫父類相應方法。

引數

                            who         需判斷的可繪製物件(Drawable)。如果是你要顯示的物件,返回True,否則返回呼叫父類的結果。

返回值

                           boolean 如果可繪製物件(Drawable)已經在檢視中顯示,返回True否則返回false。並且此處不允許使用動畫。

下面讓我們來看看如何實現這個效果把:

一.使用ToggleButton控制元件實現:

使用ToggleButton控制元件十分方便,你可以看作他為一個CheckBox,只用設定它的button、background等幾個屬性即可。

首先:res--建立drawable資料夾 -- 建立switch_btn.xml資原始檔--作以下配置

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <selector
  3.   xmlns:android="http://schemas.android.com/apk/res/android">
  4.     <itemandroid:state_checked="true"android:drawable="@drawable/ios7_switch_on"/>
  5.     <itemandroid:drawable="@drawable/ios7_switch_off"/>
  6. </selector>
其中:android:state_checked="true" 表示選中on時候的,效果為:android:drawable="@drawable/ios7_switch_on" 

     反之就是未選中off情況下的效果:android:drawable="@drawable/ios7_switch_off"

之後在佈局檔案中寫控制元件:

  1. <ToggleButton
  2.         android:id="@+id/mTogBtn"
  3.         android:layout_width="wrap_content"
  4.         android:layout_height="wrap_content"
  5.         android:layout_gravity="center_horizontal"
  6.         android:background="@android:color/transparent"
  7.         android:button="@drawable/toggle_btn"
  8.         android:checked="false"
  9.         android:text=""
  10.         android:textOff=""
  11.         android:textOn=""/>
這裡的    

android:textOn=""   表示:選中情況下顯示的文字

android:textOff=""   表示:未選中情況下顯示的文字

android:checked="false"  表示:初始化時候,預設是未選中的

android:button="@drawable/toggle_btn"  表示:button樣式

android:background="@android:color/transparent"  表示:背景,這裡不用它的預設背景,所以設定為透明

之後在主程式中例項化,並設定checked點選監聽

  1. ToggleButton mTogBtn = (ToggleButton) findViewById(R.id.mTogBtn); // 獲取到控制元件
  2. mTogBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() {  
  3.     @Override
  4.     publicvoid onCheckedChanged(CompoundButton buttonView,boolean isChecked) {  
  5.         // TODO Auto-generated method stub
  6.         if(isChecked){  
  7.             //選中
  8.         }else{  
  9.             //未選中
  10.         }  
  11.     }  
  12. });// 新增監聽事件
這樣ToggleButton的開關切換就輕鬆實現了。

二.重寫CompoundButton控制元件實現帶滑動效果的開關按鈕:

    重寫CompuundButton的實現可能會顯得相對繁瑣些,主要是考慮狀態是否已經選中等情況的文字顯示。

    可以檢視官方文件,之後繼承CompuundButton,在佈局的動畫和顯示上呼叫onDraw(Canvas canvas)重畫既可以,如果想要加入拖動屬性,那麼在該VIEW內重寫觸控事件onTouchEvent(MotionEvent ev)在裡面判斷拖動距離,之後根據拖動情況判斷開關是on還是off。

    由於繼承的是CompoundButton,所以裡面的監聽方法,setChecked等方法都是自帶的,繼承下來寫操作就可以了,不用自己在去加判斷什麼的屬性了。

    由於DEMO中的繼承CompoundButton的SwitchButton是使用自定義配置的,所以如果不瞭解自定義配置的可以看以下文章:android 自定義控制元件 使用declare-styleable進行配置屬性(原始碼角度)

    具體的這邊不貼程式碼了,可以檢視DEMO裡面的,都有註釋。

三.重寫CheckBox控制元件實現帶滑動效果的開關按鈕:

    其實,看上面給的開發文件內容,大家都可以知道,CheckBox其實就是繼承CompoundButton控制元件的,只是重構CheckBox會比CompoundButton方便好多,裡面的很多方法都是寫好的,只要自己去判斷觸控事件onTouchEvent(MotionEvent ev),以及onDraw(Canvas canvas)重畫就可以。這裡DEMO中使用到的是第3放庫內的一個控制元件,大致操作和上面其實大同小異。

四.重寫View實現帶滑動效果的開關按鈕:

   眾所周知,以上所有的控制元件都是繼承了View這個父類,所以,如果你用View去操作的話,就沒有自帶方法的限制,可是要滿足你要 實現的SwitchButton效果,你必須自己寫開關狀態監聽介面,並且自己寫setChecked方法實現同等的效果。在優化方面要自己多加細心考慮。其他操作與以上控制元件的重構大同小異。

注意:由於狀態切換等,enabled屬性改變等,是你自定義的方法內的話,你必須自己去呼叫invalidate();方法,去讓UI判斷是否有更改並做出相應的變化。

例如:

  1. @Override
  2. publicvoid setEnabled(boolean enabled) {  
  3.     // TODO Auto-generated method stub
  4.     mEnabled = enabled;  
  5.     mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;  
  6.     Log.d("enabled",enabled ? "true""false");  
  7.     super.setEnabled(enabled);  
  8.     invalidate();  
  9. }  
  10. /** 自動判斷切換至相反的屬性 : true -->false ;false -->true */
  11. publicvoid toggle() {  
  12.     setChecked(!mSwitchOn);  
  13. }  
  14.    /** 設定選中的狀態(選中:true   非選中: false) */
  15.    publicvoid setChecked(boolean checked) {  
  16.     mSwitchOn = checked;  
  17.        invalidate();  
  18.    }  
還有,你如果是自定義的VIEW,你在裡面設定了enabled屬性,你必須在onTouchEvent(MotionEvent event)觸控操作的時候判斷你所設定的enabled屬性是否為true,是的話就可以相應點選事件,否則的話你要遮蔽掉點選事件。因為你自定義的view中的enabled屬性並不知道他設定後會達到什麼效果,這些都是要注意的點。

還有就是要設定介面監聽狀態變化:

  1. /**  
  2.  * 設定 switch 狀態監聽  
  3.  * */
  4. publicvoid setOnChangeListener(OnSwitchChangedListener listener) {  
  5.     switchListener = listener;  
  6. }  
  7. /**  
  8.  * switch 開關監聽介面 
  9.  *  */
  10. publicinterface OnSwitchChangedListener{  
  11.     publicvoid onSwitchChange(SlideSwitchView switchView, boolean isChecked);  
  12. }  

有的人可能會希望有SwitchButton在enabled設定為false的時候,SwitchButton不能點選且要改變顏色,使他看過去是不能點選的。你可以進行如下操作(在學習別的人程式碼中得到的提示,學以致用):

先初始化透明度:255為不透明

  1. /** 最大透明度,就是不透明 */
  2. privatefinalint MAX_ALPHA = 255;  
  3. /** 當前透明度,這裡主要用於如果控制元件的enable屬性為false時候設定半透明 ,即不可以點選 */
  4. privateint mAlpha = MAX_ALPHA;  
之後重寫setEnabled方法,通過這個方法判斷enabled屬性值
  1. @Override
  2. publicvoid setEnabled(boolean enabled) {  
  3.     // TODO Auto-generated method stub
  4.     mEnabled = enabled;  
  5.     mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;  
  6.     super.setEnabled(enabled);  
  7.     invalidate();  
  8. }  
如果改變了enabled屬性,系統便會檢視UI是否需要變化,之後在UI方法onDraw(Canvas canvas)中呼叫:
  1. android.graphics.Canvas.saveLayerAlpha(RectF bounds, int alpha, int saveFlags)  
方法,其中的第2個屬性alpha就是透明度,之後便可以實現相應的效果。

由於目前對於重寫VIEW的onDraw方法的瞭解不是很深入,所以這裡的DEMO中的幾個方法都是檢視網路之後加上自己的優化和註釋演變過來,等這一塊深入了後在重寫寫一篇關於這個的感受和使用說明。由於可能理解不是很深刻,如果有什麼不足之處可以提出,謝謝。

最後讓我們來看看效果如何,上圖:

                      

最後上原始碼DEMO:下載地址