您好,登錄后才能下訂單哦!
這篇文章主要講解了“Android怎么實現自定義開關按鈕”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Android怎么實現自定義開關按鈕”吧!
我們在界面的某一個區域里放置一個背景圖A,這個圖片一邊為“開”,一邊為“關”,在這個圖片上放置一個圖片B,圖B大約為圖A的一半,恰好可以覆蓋掉圖A上的“開”或者“關”,當我們手指點擊圖片的時候,圖B在圖A上滑動,相應的覆蓋“開”或者“關”,這樣就實現了開關按鈕的效果。
這個類繼承自View類同時實現了OnTouchListener接口,這個類實現的功能比較多,我們分解來看這個類。
這個類中定義了不少的屬性字段,每個屬性字段的具體含義詳見代碼注釋
具體實現代碼如下:
//開關開啟的背景圖片 private Bitmap bkgSwitchOn; //開關關閉的背景圖片 private Bitmap bkgSwitchOff; //開關的滾動圖片 private Bitmap btnSlip; //當前開關是否為開啟狀態 private boolean toggleStateOn; //開關狀態的監聽事件 private OnToggleStateListener toggleStateListener; //記錄開關·當前的狀態 private boolean isToggleStateListenerOn; //手指按下屏幕時的x坐標 private float proX; //手指滑動過程中當前x坐標 private float currentX; //是否處于滑動狀態 private boolean isSlipping; //記錄上一次開關的狀態 private boolean proToggleState \= true; //開關開啟時的矩形 private Rect rect\_on; //開關關閉時的矩形 private Rect rect\_off;
我們在構造方法里完成的操作就是調用我們自己創建的init()方法
具體實現代碼如下:
public MyToggle(Context context) { super(context); init(context); } public MyToggle(Context context, AttributeSet attrs) { super(context, attrs); init(context); }
這個方法中實現的操作就是設置觸摸事件。
具體實現代碼如下:
//初始化方法 private void init(Context context) { setOnTouchListener(this); }
這個方法是當手指操作手機屏幕時,Android自動回調的方法,我們在這個方法中,監聽手指的按下、移動和抬起事件,記錄手指當前的X坐標來判斷圖片B的移動方向,從而實現圖片B在圖片A上的移動來達到按鈕開和關的效果。
具體實現代碼如下:
@Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION\_DOWN: //記錄手指按下時的x坐標 proX \= event.getX(); currentX \= proX; //將滑動標識設置為true isSlipping \= true; break; case MotionEvent.ACTION\_MOVE: //記錄手指滑動過程中當前x坐標 currentX \= event.getX(); break; case MotionEvent.ACTION\_UP: //手指抬起時將是否滑動的標識設置為false isSlipping \= false; //處于關閉狀態 if(currentX < bkgSwitchOn.getWidth() / 2 ){ toggleStateOn \= false; } else { // 處于開啟狀態 toggleStateOn \= true; } // 如果使用了開關監聽器,同時開關的狀態發生了改變,這時使用該代碼 if(isToggleStateListenerOn && toggleStateOn != proToggleState){ proToggleState \= toggleStateOn; toggleStateListener.onToggleState(toggleStateOn); } break; } invalidate();//重繪 return true; }
這個方法主要實現的是界面的重繪操作。
只要的思路是:
畫背景圖A:
當前手指滑動X坐標currentX大于圖A寬度的一般時,按鈕背景為開啟狀態;
當前手指滑動X坐標currentX小于圖A寬度的一般時,按鈕背景為關閉狀態;
記錄滑塊B的X坐標:
B滑動時:
當前手指滑動X坐標currentX大于背景圖A的寬度,則B坐標為圖A寬度減去圖B寬度
當前手指滑動X坐標currentX小于背景圖A的寬度,則B坐標為當前X坐標currentX減去滑塊寬度的一半
B靜止:
當按鈕處于“開”狀態,則B坐標為“開”狀態的最左邊X坐標
當按鈕處于“關”狀態,則B坐標為“關”狀態的最左邊X坐標
具體實現代碼如下:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //用來記錄我們滑動塊的位置 int left\_slip \= 0; Matrix matrix \= new Matrix(); Paint paint \= new Paint(); if(currentX < bkgSwitchOn.getWidth() / 2){ //在畫布上繪制出開關狀態為關閉時的 背景圖片 canvas.drawBitmap(bkgSwitchOff, matrix, paint); }else{ //在畫布上繪制出開關狀態為開啟時的 背景圖片 canvas.drawBitmap(bkgSwitchOn, matrix, paint); } if(isSlipping){//開關是否處于滑動狀態 // 滑動塊 是否超過了整個滑動按鈕的寬度 if(currentX \> bkgSwitchOn.getWidth()){ //指定滑動塊的位置 left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth(); } else { //設置當前滑動塊的位置 left\_slip \= (int) (currentX \- btnSlip.getWidth() /2); } } else {//開關是否處于 不滑動狀態 if(toggleStateOn){ left\_slip \= rect\_on.left; } else { left\_slip \= rect\_off.left; } } if(left\_slip < 0){ left\_slip \= 0; } else if( left\_slip \> bkgSwitchOn.getWidth() \- btnSlip.getWidth()){ left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth(); } //繪制圖像 canvas.drawBitmap(btnSlip, left\_slip, 0, paint); }
這里我通過覆寫onMeasure來計算開關的寬度和高度
具體實現代碼如下:
//計算開關的寬高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(bkgSwitchOn.getWidth(), bkgSwitchOn.getHeight()); }
這個方法主要是供外界調用,向本類提供圖片資源。
具體代碼實現如下:
/\*\* \* 設置圖片資源信息 \* @param bkgSwitch\_on \* @param bkgSwitch\_off \* @param btn\_Slip \*/ public void setImageRes(int bkgSwitch\_on, int bkgSwitch\_off, int btn\_Slip) { bkgSwitchOn \= BitmapFactory.decodeResource(getResources(), bkgSwitch\_on); bkgSwitchOff \= BitmapFactory.decodeResource(getResources(),bkgSwitch\_off); btnSlip \= BitmapFactory.decodeResource(getResources(), btn\_Slip); rect\_on \= new Rect(bkgSwitchOn.getWidth() \- btnSlip.getWidth(), 0,bkgSwitchOn.getWidth(), btnSlip.getHeight()); rect\_off \= new Rect(0, 0, btnSlip.getWidth(), btnSlip.getHeight()); }
通過傳遞一個boolean類型的狀態,我們在這個方法中將這個狀態標識記錄下來。
具體實現代碼如下:
/\*\* \* 設置開關按鈕的狀態 \* @param state \*/ public void setToggleState(boolean state) { toggleStateOn \= state; }
我在這個類中定義了一個開關狀態監聽器接口OnToggleStateListener,里面有一個onToggleState方法來執行按鈕的狀態變化監聽操作。
具體代碼實現如下:
/\*\* \* 自定義開關狀態監聽器 \* @author liuyazhuang \* \*/ interface OnToggleStateListener { abstract void onToggleState(boolean state); }
創建setOnToggleStateListener方法,傳遞一個OnToggleStateListener監聽器對象,通過外界創建OnToggleStateListener對象,并將OnToggleStateListener對象傳遞進來,我們只需要將外界傳遞過來的OnToggleStateListener對象記錄下來,同時當我們調用OnToggleStateListener接口中的onToggleState方法時,便實現了回調外界OnToggleStateListener實現類中的onToggleState方法。
具體代碼實現如下:
//設置開關監聽器并將是否設置了開關監聽器設置為true public void setOnToggleStateListener(OnToggleStateListener listener) { toggleStateListener \= listener; isToggleStateListenerOn \= true; }
package com.lyz.slip.toggle; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; /\*\* \* 自定義開關類 \* @author liuyazhuang \* \*/ public class MyToggle extends View implements OnTouchListener { //開關開啟的背景圖片 private Bitmap bkgSwitchOn; //開關關閉的背景圖片 private Bitmap bkgSwitchOff; //開關的滾動圖片 private Bitmap btnSlip; //當前開關是否為開啟狀態 private boolean toggleStateOn; //開關狀態的監聽事件 private OnToggleStateListener toggleStateListener; //記錄開關·當前的狀態 private boolean isToggleStateListenerOn; //手指按下屏幕時的x坐標 private float proX; //手指滑動過程中當前x坐標 private float currentX; //是否處于滑動狀態 private boolean isSlipping; //記錄上一次開關的狀態 private boolean proToggleState \= true; //開關開啟時的矩形 private Rect rect\_on; //開關關閉時的矩形 private Rect rect\_off; public MyToggle(Context context) { super(context); init(context); } public MyToggle(Context context, AttributeSet attrs) { super(context, attrs); init(context); } //初始化方法 private void init(Context context) { setOnTouchListener(this); } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION\_DOWN: //記錄手指按下時的x坐標 proX \= event.getX(); currentX \= proX; //將滑動標識設置為true isSlipping \= true; break; case MotionEvent.ACTION\_MOVE: //記錄手指滑動過程中當前x坐標 currentX \= event.getX(); break; case MotionEvent.ACTION\_UP: //手指抬起時將是否滑動的標識設置為false isSlipping \= false; //處于關閉狀態 if(currentX < bkgSwitchOn.getWidth() / 2 ){ toggleStateOn \= false; } else { // 處于開啟狀態 toggleStateOn \= true; } // 如果使用了開關監聽器,同時開關的狀態發生了改變,這時使用該代碼 if(isToggleStateListenerOn && toggleStateOn != proToggleState){ proToggleState \= toggleStateOn; toggleStateListener.onToggleState(toggleStateOn); } break; } invalidate();//重繪 return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //用來記錄我們滑動塊的位置 int left\_slip \= 0; Matrix matrix \= new Matrix(); Paint paint \= new Paint(); if(currentX < bkgSwitchOn.getWidth() / 2){ //在畫布上繪制出開關狀態為關閉時的 背景圖片 canvas.drawBitmap(bkgSwitchOff, matrix, paint); }else{ //在畫布上繪制出開關狀態為開啟時的 背景圖片 canvas.drawBitmap(bkgSwitchOn, matrix, paint); } if(isSlipping){//開關是否處于滑動狀態 // 滑動塊 是否超過了整個滑動按鈕的寬度 if(currentX \> bkgSwitchOn.getWidth()){ //指定滑動塊的位置 left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth(); } else { //設置當前滑動塊的位置 left\_slip \= (int) (currentX \- btnSlip.getWidth() /2); } } else {//開關是否處于 不滑動狀態 if(toggleStateOn){ left\_slip \= rect\_on.left; } else { left\_slip \= rect\_off.left; } } if(left\_slip < 0){ left\_slip \= 0; } else if( left\_slip \> bkgSwitchOn.getWidth() \- btnSlip.getWidth()){ left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth(); } //繪制圖像 canvas.drawBitmap(btnSlip, left\_slip, 0, paint); } //計算開關的寬高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(bkgSwitchOn.getWidth(), bkgSwitchOn.getHeight()); } /\*\* \* 設置圖片資源信息 \* @param bkgSwitch\_on \* @param bkgSwitch\_off \* @param btn\_Slip \*/ public void setImageRes(int bkgSwitch\_on, int bkgSwitch\_off, int btn\_Slip) { bkgSwitchOn \= BitmapFactory.decodeResource(getResources(), bkgSwitch\_on); bkgSwitchOff \= BitmapFactory.decodeResource(getResources(),bkgSwitch\_off); btnSlip \= BitmapFactory.decodeResource(getResources(), btn\_Slip); rect\_on \= new Rect(bkgSwitchOn.getWidth() \- btnSlip.getWidth(), 0,bkgSwitchOn.getWidth(), btnSlip.getHeight()); rect\_off \= new Rect(0, 0, btnSlip.getWidth(), btnSlip.getHeight()); } /\*\* \* 設置開關按鈕的狀態 \* @param state \*/ public void setToggleState(boolean state) { toggleStateOn \= state; } /\*\* \* 自定義開關狀態監聽器 \* @author liuyazhuang \* \*/ interface OnToggleStateListener { abstract void onToggleState(boolean state); } //設置開關監聽器并將是否設置了開關監聽器設置為true public void setOnToggleStateListener(OnToggleStateListener listener) { toggleStateListener \= listener; isToggleStateListenerOn \= true; } }
這個類實現很簡單,主要的功能就是加載界面布局,初始化界面控件,調用MyToggle類中的方法實現按鈕的開關效果
具體代碼實現如下:
package com.lyz.slip.toggle; import android.app.Activity; import android.os.Bundle; import android.widget.Toast; import com.lyz.slip.toggle.MyToggle.OnToggleStateListener; /\*\* \* 程序主入口 \* @author liuyazhuang \* \*/ public class MainActivity extends Activity { //自定義開關對象 private MyToggle toggle; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity\_main); toggle \= (MyToggle) findViewById(R.id.toggle); //設置開關顯示所用的圖片 toggle.setImageRes(R.drawable.bkg\_switch, R.drawable.bkg\_switch, R.drawable.btn\_slip); //設置開關的默認狀態 true開啟狀態 toggle.setToggleState(true); //設置開關的監聽 toggle.setOnToggleStateListener(new OnToggleStateListener() { @Override public void onToggleState(boolean state) { // TODO Auto-generated method stub if(state){ Toast.makeText(getApplicationContext(), "開關開啟", 0).show(); } else { Toast.makeText(getApplicationContext(), "開關關閉", 0).show(); } } }); } }
這里我引用了自己定義的View類MyToggle。
具體代碼實現如下:
<RelativeLayout xmlns:android\="http://schemas.android.com/apk/res/android" xmlns:tools\="http://schemas.android.com/tools" android:layout\_width\="match\_parent" android:layout\_height\="match\_parent" \> <com.lyz.slip.toggle.MyToggle android:id\="@+id/toggle" android:layout\_width\="wrap\_content" android:layout\_height\="wrap\_content" android:layout\_centerInParent\="true"/> </RelativeLayout\>
具體代碼如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android\="http://schemas.android.com/apk/res/android" package\="com.lyz.slip.toggle" android:versionCode\="1" android:versionName\="1.0" \> <uses-sdk android:minSdkVersion\="10" android:targetSdkVersion\="18" /> <application android:allowBackup\="true" android:icon\="@drawable/ic\_launcher" android:label\="@string/app\_name" android:theme\="@style/AppTheme" \> <activity android:name\="com.lyz.slip.toggle.MainActivity" android:label\="@string/app\_name" \> <intent-filter\> <action android:name\="android.intent.action.MAIN" /> <category android:name\="android.intent.category.LAUNCHER" /> </intent-filter\> </activity\> </application\> </manifest\>
感謝各位的閱讀,以上就是“Android怎么實現自定義開關按鈕”的內容了,經過本文的學習后,相信大家對Android怎么實現自定義開關按鈕這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。