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資原始檔--作以下配置
- <?xmlversion="1.0"encoding="utf-8"?>
- <selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <itemandroid:state_checked="true"android:drawable="@drawable/ios7_switch_on"/>
- <itemandroid:drawable="@drawable/ios7_switch_off"/>
- </selector>
反之就是未選中off情況下的效果:android:drawable="@drawable/ios7_switch_off"
之後在佈局檔案中寫控制元件:
- <ToggleButton
- android:id="@+id/mTogBtn"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:background="@android:color/transparent"
- android:button="@drawable/toggle_btn"
- android:checked="false"
- android:text=""
- android:textOff=""
- android:textOn=""/>
android:textOn="" 表示:選中情況下顯示的文字
android:textOff="" 表示:未選中情況下顯示的文字
android:checked="false" 表示:初始化時候,預設是未選中的
android:button="@drawable/toggle_btn" 表示:button樣式
android:background="@android:color/transparent" 表示:背景,這裡不用它的預設背景,所以設定為透明
之後在主程式中例項化,並設定checked點選監聽
- ToggleButton mTogBtn = (ToggleButton) findViewById(R.id.mTogBtn); // 獲取到控制元件
- mTogBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- publicvoid onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
- // TODO Auto-generated method stub
- if(isChecked){
- //選中
- }else{
- //未選中
- }
- }
- });// 新增監聽事件
二.重寫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判斷是否有更改並做出相應的變化。
例如:
- @Override
- publicvoid setEnabled(boolean enabled) {
- // TODO Auto-generated method stub
- mEnabled = enabled;
- mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
- Log.d("enabled",enabled ? "true": "false");
- super.setEnabled(enabled);
- invalidate();
- }
- /** 自動判斷切換至相反的屬性 : true -->false ;false -->true */
- publicvoid toggle() {
- setChecked(!mSwitchOn);
- }
- /** 設定選中的狀態(選中:true 非選中: false) */
- publicvoid setChecked(boolean checked) {
- mSwitchOn = checked;
- invalidate();
- }
還有就是要設定介面監聽狀態變化:
- /**
- * 設定 switch 狀態監聽
- * */
- publicvoid setOnChangeListener(OnSwitchChangedListener listener) {
- switchListener = listener;
- }
- /**
- * switch 開關監聽介面
- * */
- publicinterface OnSwitchChangedListener{
- publicvoid onSwitchChange(SlideSwitchView switchView, boolean isChecked);
- }
有的人可能會希望有SwitchButton在enabled設定為false的時候,SwitchButton不能點選且要改變顏色,使他看過去是不能點選的。你可以進行如下操作(在學習別的人程式碼中得到的提示,學以致用):
先初始化透明度:255為不透明
- /** 最大透明度,就是不透明 */
- privatefinalint MAX_ALPHA = 255;
- /** 當前透明度,這裡主要用於如果控制元件的enable屬性為false時候設定半透明 ,即不可以點選 */
- privateint mAlpha = MAX_ALPHA;
- @Override
- publicvoid setEnabled(boolean enabled) {
- // TODO Auto-generated method stub
- mEnabled = enabled;
- mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
- super.setEnabled(enabled);
- invalidate();
- }
- android.graphics.Canvas.saveLayerAlpha(RectF bounds, int alpha, int saveFlags)
由於目前對於重寫VIEW的onDraw方法的瞭解不是很深入,所以這裡的DEMO中的幾個方法都是檢視網路之後加上自己的優化和註釋演變過來,等這一塊深入了後在重寫寫一篇關於這個的感受和使用說明。由於可能理解不是很深刻,如果有什麼不足之處可以提出,謝謝。
最後讓我們來看看效果如何,上圖:
最後上原始碼DEMO:下載地址