剛開始接觸開關樣式的按鈕是在IOS系統上面,它的切換以及滑動十分帥氣,深入人心。
所謂的開關按鈕,就是只有2個狀態:on和off,下圖就是系統IOS 7上開關按鈕效果。
起初我在android上我只會使用CheckBox去滿足對應的功能。后來,查看開發文檔發現,android也有了自己的原生態開關控件,並且在4.0版本中又優化加入了新的類似控件--Switch控件,以及使用起來十分簡單的ToggleButton,可是它們只是帶有切換效果,而不帶有滑動切換效果,並且Switch控件只支持高版本的系統,對於2.3就不支持。所以,要想看如何實現滑動切換的效果,必須了解這些控件的實現方式。下面,讓我們查看下android開發文檔,看看這些是如何實現使用的。
注意:本文中涉及到自定義控件 並自定義配置屬性declare-styleable,
如果你對於自定義控件的自定義配置屬性還不是很了解可以看:android 自定義控件 使用declare-styleable進行配置屬性(源碼角度)
查看查看開發文檔:
CompoundButton
extends Button
implements Checkable
↳ |
||||
|
↳ |
|||
|
|
↳ |
||
|
|
|
↳ |
android.widget.CompoundButton |
Known Direct Subclasses |
以上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 |
getCompoundPaddingLeft()Returns the left padding of the view, plus space for the left Drawable if any. |
int |
getCompoundPaddingRight()Returns the right padding of the view, plus space for the right Drawable if any. |
boolean:是否被選中。
boolean |
設置Button的Drawable屬性
void |
setButtonDrawable(int resid)Set the background to a given Drawable, identified by its resource id. |
設置是否選中
void |
setChecked(boolean checked)Changes the checked state of this button. |
改變當前的狀態,true-->false ;false-->true
void |
toggle()Change the checked state of the view to the inverse of its current state |
控件全局 繪制
void |
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資源文件--作以下配置
- <?xml version="1.0" encoding="utf-8"?>
- <selector
- xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_checked="true" android:drawable="@drawable/ios7_switch_on" />
- <item android:drawable="@drawable/ios7_switch_off" />
- </selector>
其中:android:state_checked="true" 表示選中on時候的,效果為:android:drawable="@drawable/ios7_switch_on"
反之就是未選中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
- public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
- // TODO Auto-generated method stub
- if(isChecked){
- //選中
- }else{
- //未選中
- }
- }
- });// 添加監聽事件
這樣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判斷是否有更改並做出相應的變化。
例如:
- @Override
- public void 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 */
- public void toggle() {
- setChecked(!mSwitchOn);
- }
- /** 設置選中的狀態(選中:true 非選中: false) */
- public void setChecked(boolean checked) {
- mSwitchOn = checked;
- invalidate();
- }
還有,你如果是自定義的VIEW,你在里面設置了enabled屬性,你必須在onTouchEvent(MotionEvent event)觸摸操作的時候判斷你所設置的enabled屬性是否為true,是的話就可以相應點擊事件,否則的話你要屏蔽掉點擊事件。因為你自定義的view中的enabled屬性並不知道他設定后會達到什么效果,這些都是要注意的點。
還有就是要設置接口監聽狀態變化:
- /**
- * 設置 switch 狀態監聽
- * */
- public void setOnChangeListener(OnSwitchChangedListener listener) {
- switchListener = listener;
- }
- /**
- * switch 開關監聽接口
- * */
- public interface OnSwitchChangedListener{
- public void onSwitchChange(SlideSwitchView switchView, boolean isChecked);
- }
有的人可能會希望有SwitchButton在enabled設置為false的時候,SwitchButton不能點擊且要改變顏色,使他看過去是不能點擊的。你可以進行如下操作(在學習別的人代碼中得到的提示,學以致用):
先初始化透明度:255為不透明
- /** 最大透明度,就是不透明 */
- private final int MAX_ALPHA = 255;
- /** 當前透明度,這里主要用於如果控件的enable屬性為false時候設置半透明 ,即不可以點擊 */
- private int mAlpha = MAX_ALPHA;
之后重寫setEnabled方法,通過這個方法判斷enabled屬性值
- @Override
- public void setEnabled(boolean enabled) {
- // TODO Auto-generated method stub
- mEnabled = enabled;
- mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;
- super.setEnabled(enabled);
- invalidate();
- }
如果改變了enabled屬性,系統便會查看UI是否需要變化,之后在UI方法onDraw(Canvas canvas)中調用:
- android.graphics.Canvas.saveLayerAlpha(RectF bounds, int alpha, int saveFlags)
方法,其中的第2個屬性alpha就是透明度,之后便可以實現相應的效果。
由於目前對於重寫VIEW的onDraw方法的了解不是很深入,所以這里的DEMO中的幾個方法都是查看網絡之后加上自己的優化和注釋演變過來,等這一塊深入了后在重寫寫一篇關於這個的感受和使用說明。由於可能理解不是很深刻,如果有什么不足之處可以提出,謝謝。
最后讓我們來看看效果如何,上圖:
最后上源碼DEMO:下載地址