Android自訂控制項——仿ios開關按鈕

來源:互聯網
上載者:User

Android自訂控制項——仿ios開關按鈕

 

大凡在公司做用戶端產品開發的都會發現,android和ios的差異化,ios得益於“老喬”的精心設計,介面使用者體驗做到了極致,而android秉承開源思想,介面使用者體驗百家各有其長,相互不得統一。不說廢話,先,看看ios的“開關按鈕”:

 

往往在公司,產品設計原型優先參考了ios的設計,這下可苦了android開發人員,android開發人員被迫要寫和ios幾乎同樣的效果,這種情況應該很常見吧!例如,下面我提到的“開關按鈕”,在ios中是整合好的,拿來就用,但在android裡面確實在android 4.0以後才出現ToggleButton的組件,拋開介面不談(實際不是很美觀),那麼看相容性吧,ToggleButton是從4.0以後才開始有的東西,那麼2.3的系統我們不能就此忽略了吧,2.3在市場佔有上還是有很大比重的。因此,能做到和ios同樣效果的“開關按鈕”,我們只能“苦逼的”用java代碼去繪製出這樣一個組件了。

簡單講講自繪組件的方法,Android下自繪組件大致分為繼承View和繼承ViewGroup兩種。

實現步驟和對應的方法:
測量寬高 --> 排版(布置控制項的位置) --> 繪製到螢幕
| | |
onMeasure onLayout onDraw
值得注意的是:自訂群組件若是繼承ViewGroup來實現,就必須實現上述3個步驟,尤其是排版,這裡需要制定組件的顯示位置。自訂群組件是繼承View來實現的話,排版這步不需要了,只完成測量和繪製即可。

以下我的項目Demo結構圖:

自訂“開關按鈕”主要實現代碼:

 

package com.example.slidebutton.view;import com.example.slidebutton.R;import com.example.slidebutton.view.interf.OnToggleStateChangeListener;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;public class SlideButton extends View {/** 滑動開關的背景 */private Bitmap slideButtonBG;/** 滑動塊的背景 */private Bitmap switchBG;/** 設定開關的狀態,開啟/關閉。 預設:關閉 */private boolean currentState = false;/** 當前滑動塊的移動距離 */private int currentX;/** 記錄當前滑動塊滑動的狀態。預設,false */private boolean isSliding = false;/** 開關狀態改變監聽 */private OnToggleStateChangeListener mListener;public SlideButton(Context context, AttributeSet attrs) {super(context, attrs);initBitmap();}private void initBitmap() {slideButtonBG = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button_background);switchBG = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);}/** * 移動效果的處理 */@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN: // 手指按下currentX = (int) event.getX();isSliding = true;break;case MotionEvent.ACTION_MOVE: // 手指移動currentX = (int) event.getX();break;case MotionEvent.ACTION_UP: // 手指抬起isSliding = false;// 判斷當前滑動塊,偏向於哪一邊,如果滑動塊的中心點<背景的中心點,設定為關閉狀態int bgCenter = switchBG.getWidth() / 2;boolean state = currentX >= bgCenter; // 改變後的狀態// 手指抬起時,回調監聽,返回當前的開關狀態if (state != currentState && mListener != null) {mListener.onToggleStateChange(state);}currentState = state;break;default:break;}invalidate(); // 重新整理控制項,該方法會調用onDraw(Canvas canvas)方法return true; // 自己處理事件,不讓父類負責消耗事件}/** * 測量當前控制項寬高時回調 */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);// 設定開關的寬和高setMeasuredDimension(switchBG.getWidth(), switchBG.getHeight());}/** * 繪製控制項 */@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);// 1,滑動開關背景繪製到控制項canvas.drawBitmap(switchBG, 0, 0, null);// 2,繪製滑動塊顯示的位置,開啟或關閉if (isSliding) {int left = currentX - slideButtonBG.getWidth() / 2; // 處理手指觸點,將觸點從slidingButton的左邊移動到中間if (left < 0) {left = 0;} else if (left > switchBG.getWidth() - slideButtonBG.getWidth()) {left = switchBG.getWidth() - slideButtonBG.getWidth();}canvas.drawBitmap(slideButtonBG, left, 0, null);} else {if (currentState) {// 繪製開啟狀態canvas.drawBitmap(slideButtonBG, switchBG.getWidth() - slideButtonBG.getWidth(), 0, null);} else {// 繪製關閉狀態canvas.drawBitmap(slideButtonBG, 0, 0, null);}}}public void setToggleState(boolean b) {currentState = b;}/** * 對外設定監聽方法 *  * @param listener */public void setOnToggleStateChangeListener(OnToggleStateChangeListener listener) {this.mListener = listener;}}
“開關按鈕”的是繼承自View來實現的,關於View的建構函式:

 

 

public SlideButton(Context context) {super(context);// TODO Auto-generated constructor stub}
該構造用於該組件僅僅在代碼中執行個體化,不能在布局檔案中聲明

 

 

public SlideButton(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}
聲明該構造後,可以在布局檔案中聲明出這個控制項,一般自訂群組件都複寫這個構造方法。

 

 

public SlideButton(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stub}
這是View的第三個構造,可以在布局檔案中聲明之外,還需要制定組件的顯示樣式,用的較少。

 

複寫父類View的構造器之後,就需要複寫View的另兩個重要的方法了,onMeasure和onDraw。onMeasure是用於測量組件的大小寬高的方法,在這裡,只處理“開關按鈕”的背景圖的寬高,使用setMeasuredDimension方法,指定測量後的值。然後在onDraw方法中,在畫布Canvas上畫出這個自訂群組件,裡面會包含一系列的邏輯判斷,請大家仔細閱讀源碼,這裡不介紹了。

為了增強“開關按鈕”的使用者體驗,需要判斷按鈕的滑動方向來確定按鈕的狀態,所以需要複寫onTouchEvent方法,在這個方法裡處理手指觸發的各種狀態。值得一提的是,在處理完手指移動的觸發後,接下來就是重繪組件,達到動態效果,這時必須在每次觸發完成時,調用一下View的invalidate()方法,該方法的作用是:重新整理控制項,該方法會調用onDraw(Canvas canvas)方法。

最後,“開發按鈕”要與使用該控制項的介面或者使用者實現互動或狀態傳遞,這裡需要寫一個Java回呼函數,用於在主介面上回調監聽“開關按鈕”的狀態,代碼如下:

 

package com.example.slidebutton.view.interf;/** * 開關狀態改變監聽事件 *  * @author Administrator *  */public interface OnToggleStateChangeListener {/** * 當開關狀態改變回調此方法 *  * @param b *            當前開關的最新狀態 */void onToggleStateChange(boolean b);}

關於監聽的內部實現,請參考SlidingButton自訂群組件代碼。這裡主要為外部參考該控制項的介面提供了一個設定監聽的方法setOnToggleStateChangeListener(OnToggleStateChangeListener listener),在判斷每次手指抬起的時候,說明開關狀態改變的過程結束,需要在那裡為監聽器設定回調參數,即當前的開關的狀態boolean變數。這樣,外部參考該控制項的介面就可以拿到這個boolean值,做出相應的處理。那麼,以下就是外部參考該自訂群組件的主要代碼:

 

布局檔案,activity_main.xml:

 

    
主介面的代碼MainActivity.java:

 

 

package com.example.slidebutton;import com.example.slidebutton.view.SlideButton;import com.example.slidebutton.view.interf.OnToggleStateChangeListener;import android.os.Bundle;import android.widget.Toast;import android.app.Activity;public class MainActivity extends Activity implements OnToggleStateChangeListener {public SlideButton slideButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);slideButton = (SlideButton) findViewById(R.id.slidebutton);slideButton.setToggleState(true);slideButton.setOnToggleStateChangeListener(this);}@Overridepublic void onToggleStateChange(boolean b) {// TODO Auto-generated method stubif (b) {Toast.makeText(MainActivity.this, 開關開啟, Toast.LENGTH_SHORT).show();} else {Toast.makeText(MainActivity.this, 開關關閉, Toast.LENGTH_SHORT).show();}}}

以下是運行:

 

以上內容,有諸多不專業不正確或者疏忽的地方,歡迎大家批評指正,共同學習~

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.