欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)史上最簡(jiǎn)單自定義開關(guān)按鈕的方法

 更新時(shí)間:2022年04月29日 17:03:42   作者:冰 河  
在平常的開發(fā)中按鈕是經(jīng)常使用到的控件之一,下面這篇文章主要給大家介紹了關(guān)于Android實(shí)現(xiàn)史上最簡(jiǎn)單自定義開關(guān)按鈕的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

很多時(shí)候,我們?cè)诤芏酂o論是Android還是IOS的APP中都會(huì)遇到這樣的一種效果,有一個(gè)按鈕,我們點(diǎn)擊一下,便會(huì)滑動(dòng)一下,一會(huì)顯示“開”,一會(huì)顯示“關(guān)”,這便是開關(guān)按鈕了,比如:很多Android手機(jī)的設(shè)置功能里,就有很多功能是用開關(guān)按鈕實(shí)現(xiàn)的,那么這些開關(guān)按鈕時(shí)如何實(shí)現(xiàn)的呢?下面,就讓我們一起來實(shí)現(xiàn)這個(gè)功能吧。

一、原理

我們?cè)诮缑娴哪骋粋€(gè)區(qū)域里放置一個(gè)背景圖A,這個(gè)圖片一邊為“開”,一邊為“關(guān)”,在這個(gè)圖片上放置一個(gè)圖片B,圖B大約為圖A的一半,恰好可以覆蓋掉圖A上的“開”或者“關(guān)”,當(dāng)我們手指點(diǎn)擊圖片的時(shí)候,圖B在圖A上滑動(dòng),相應(yīng)的覆蓋“開”或者“關(guān)”,這樣就實(shí)現(xiàn)了開關(guān)按鈕的效果。

二、實(shí)現(xiàn)

1、自定義View類MyToggle

這個(gè)類繼承自View類同時(shí)實(shí)現(xiàn)了OnTouchListener接口,這個(gè)類實(shí)現(xiàn)的功能比較多,我們分解來看這個(gè)類。

1)屬性字段

這個(gè)類中定義了不少的屬性字段,每個(gè)屬性字段的具體含義詳見代碼注釋

具體實(shí)現(xiàn)代碼如下:

//開關(guān)開啟的背景圖片  
private Bitmap bkgSwitchOn;  
//開關(guān)關(guān)閉的背景圖片  
private Bitmap bkgSwitchOff;  
//開關(guān)的滾動(dòng)圖片  
private Bitmap btnSlip;  
//當(dāng)前開關(guān)是否為開啟狀態(tài)  
private boolean toggleStateOn;  
//開關(guān)狀態(tài)的監(jiān)聽事件  
private OnToggleStateListener toggleStateListener;  
//記錄開關(guān)·當(dāng)前的狀態(tài)  
private boolean isToggleStateListenerOn;  
//手指按下屏幕時(shí)的x坐標(biāo)  
private float proX;  
//手指滑動(dòng)過程中當(dāng)前x坐標(biāo)  
private float currentX;  
//是否處于滑動(dòng)狀態(tài)  
private boolean isSlipping;  
//記錄上一次開關(guān)的狀態(tài)  
private boolean proToggleState \= true;  
//開關(guān)開啟時(shí)的矩形  
private Rect rect\_on;  
//開關(guān)關(guān)閉時(shí)的矩形  
private Rect rect\_off;

2)覆寫View類的構(gòu)造方法

我們?cè)跇?gòu)造方法里完成的操作就是調(diào)用我們自己創(chuàng)建的init()方法

具體實(shí)現(xiàn)代碼如下:

public MyToggle(Context context) {  
  super(context);  
  init(context);  
}  
  
public MyToggle(Context context, AttributeSet attrs) {  
  super(context, attrs);  
  init(context);  
}

3)創(chuàng)建init方法

這個(gè)方法中實(shí)現(xiàn)的操作就是設(shè)置觸摸事件。

具體實(shí)現(xiàn)代碼如下:

//初始化方法  
private void init(Context context) {  
  setOnTouchListener(this);  
  
}

4)手指觸摸事件回調(diào)方法onTouch

這個(gè)方法是當(dāng)手指操作手機(jī)屏幕時(shí),Android自動(dòng)回調(diào)的方法,我們?cè)谶@個(gè)方法中,監(jiān)聽手指的按下、移動(dòng)和抬起事件,記錄手指當(dāng)前的X坐標(biāo)來判斷圖片B的移動(dòng)方向,從而實(shí)現(xiàn)圖片B在圖片A上的移動(dòng)來達(dá)到按鈕開和關(guān)的效果。

具體實(shí)現(xiàn)代碼如下:

@Override  
public boolean onTouch(View v, MotionEvent event) {  
  switch (event.getAction()) {  
  case MotionEvent.ACTION\_DOWN:  
    //記錄手指按下時(shí)的x坐標(biāo)  
    proX \= event.getX();   
    currentX \= proX;  
    //將滑動(dòng)標(biāo)識(shí)設(shè)置為true  
    isSlipping \= true;  
    break;  
  
  case MotionEvent.ACTION\_MOVE:  
    //記錄手指滑動(dòng)過程中當(dāng)前x坐標(biāo)  
    currentX \= event.getX();  
    break;  
  
  case MotionEvent.ACTION\_UP:  
    //手指抬起時(shí)將是否滑動(dòng)的標(biāo)識(shí)設(shè)置為false  
    isSlipping \= false;  
    //處于關(guān)閉狀態(tài)  
    if(currentX < bkgSwitchOn.getWidth() / 2 ){  
      toggleStateOn \= false;  
    } else { // 處于開啟狀態(tài)  
      toggleStateOn \= true;  
    }  
      
    // 如果使用了開關(guān)監(jiān)聽器,同時(shí)開關(guān)的狀態(tài)發(fā)生了改變,這時(shí)使用該代碼  
    if(isToggleStateListenerOn && toggleStateOn != proToggleState){  
      proToggleState \= toggleStateOn;  
      toggleStateListener.onToggleState(toggleStateOn);  
    }  
    break;  
  }  
  invalidate();//重繪  
  return true;  
}

5)界面重繪方法onDraw

這個(gè)方法主要實(shí)現(xiàn)的是界面的重繪操作。

只要的思路是:

畫背景圖A:

    當(dāng)前手指滑動(dòng)X坐標(biāo)currentX大于圖A寬度的一般時(shí),按鈕背景為開啟狀態(tài);

    當(dāng)前手指滑動(dòng)X坐標(biāo)currentX小于圖A寬度的一般時(shí),按鈕背景為關(guān)閉狀態(tài);

記錄滑塊B的X坐標(biāo):

B滑動(dòng)時(shí):

   當(dāng)前手指滑動(dòng)X坐標(biāo)currentX大于背景圖A的寬度,則B坐標(biāo)為圖A寬度減去圖B寬度

   當(dāng)前手指滑動(dòng)X坐標(biāo)currentX小于背景圖A的寬度,則B坐標(biāo)為當(dāng)前X坐標(biāo)currentX減去滑塊寬度的一半

B靜止:

   當(dāng)按鈕處于“開”狀態(tài),則B坐標(biāo)為“開”狀態(tài)的最左邊X坐標(biāo)

   當(dāng)按鈕處于“關(guān)”狀態(tài),則B坐標(biāo)為“關(guān)”狀態(tài)的最左邊X坐標(biāo)

具體實(shí)現(xiàn)代碼如下:

@Override  
protected void onDraw(Canvas canvas) {  
  super.onDraw(canvas);  
  //用來記錄我們滑動(dòng)塊的位置  
  int left\_slip \= 0;   
  Matrix matrix \= new Matrix();  
  Paint paint \= new Paint();  
  if(currentX < bkgSwitchOn.getWidth() / 2){  
    //在畫布上繪制出開關(guān)狀態(tài)為關(guān)閉時(shí)的  背景圖片  
    canvas.drawBitmap(bkgSwitchOff, matrix, paint);  
  }else{  
    //在畫布上繪制出開關(guān)狀態(tài)為開啟時(shí)的  背景圖片  
    canvas.drawBitmap(bkgSwitchOn, matrix, paint);  
  }  
  if(isSlipping){//開關(guān)是否處于滑動(dòng)狀態(tài)  
    // 滑動(dòng)塊 是否超過了整個(gè)滑動(dòng)按鈕的寬度   
    if(currentX \> bkgSwitchOn.getWidth()){  
      //指定滑動(dòng)塊的位置  
      left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth();  
    } else {  
      //設(shè)置當(dāng)前滑動(dòng)塊的位置  
      left\_slip \= (int) (currentX \- btnSlip.getWidth() /2);  
    }  
  } else {//開關(guān)是否處于   不滑動(dòng)狀態(tài)   
    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);  
}

6)計(jì)算開關(guān)的寬高

這里我通過覆寫onMeasure來計(jì)算開關(guān)的寬度和高度

具體實(shí)現(xiàn)代碼如下:

//計(jì)算開關(guān)的寬高  
@Override  
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  setMeasuredDimension(bkgSwitchOn.getWidth(), bkgSwitchOn.getHeight());  
}

7)設(shè)置圖片資源信息

這個(gè)方法主要是供外界調(diào)用,向本類提供圖片資源。

具體代碼實(shí)現(xiàn)如下:

/\*\*  
 \* 設(shè)置圖片資源信息  
 \* @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());  
}

8)設(shè)置開關(guān)按鈕的狀態(tài)

通過傳遞一個(gè)boolean類型的狀態(tài),我們?cè)谶@個(gè)方法中將這個(gè)狀態(tài)標(biāo)識(shí)記錄下來。

具體實(shí)現(xiàn)代碼如下:

/\*\*  
 \* 設(shè)置開關(guān)按鈕的狀態(tài)  
 \* @param state  
 \*/  
public void setToggleState(boolean state) {  
  toggleStateOn \= state;  
}

9)自定義開關(guān)狀態(tài)監(jiān)聽器

我在這個(gè)類中定義了一個(gè)開關(guān)狀態(tài)監(jiān)聽器接口OnToggleStateListener,里面有一個(gè)onToggleState方法來執(zhí)行按鈕的狀態(tài)變化監(jiān)聽操作。

具體代碼實(shí)現(xiàn)如下:

/\*\*  
 \* 自定義開關(guān)狀態(tài)監(jiān)聽器  
 \* @author liuyazhuang  
 \*  
 \*/  
interface OnToggleStateListener {  
  abstract void onToggleState(boolean state);  
}

10)設(shè)置開關(guān)監(jiān)聽器

創(chuàng)建setOnToggleStateListener方法,傳遞一個(gè)OnToggleStateListener監(jiān)聽器對(duì)象,通過外界創(chuàng)建OnToggleStateListener對(duì)象,并將OnToggleStateListener對(duì)象傳遞進(jìn)來,我們只需要將外界傳遞過來的OnToggleStateListener對(duì)象記錄下來,同時(shí)當(dāng)我們調(diào)用OnToggleStateListener接口中的onToggleState方法時(shí),便實(shí)現(xiàn)了回調(diào)外界OnToggleStateListener實(shí)現(xiàn)類中的onToggleState方法。

具體代碼實(shí)現(xiàn)如下:

//設(shè)置開關(guān)監(jiān)聽器并將是否設(shè)置了開關(guān)監(jiān)聽器設(shè)置為true  
public void setOnToggleStateListener(OnToggleStateListener listener) {  
  toggleStateListener \= listener;  
  isToggleStateListenerOn \= true;  
}

11)MyToggle完整代碼如下:

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;  
  
/\*\*  
 \* 自定義開關(guān)類  
 \* @author liuyazhuang  
 \*  
 \*/  
public class MyToggle extends View implements OnTouchListener {  
  //開關(guān)開啟的背景圖片  
  private Bitmap bkgSwitchOn;  
  //開關(guān)關(guān)閉的背景圖片  
  private Bitmap bkgSwitchOff;  
  //開關(guān)的滾動(dòng)圖片  
  private Bitmap btnSlip;  
  //當(dāng)前開關(guān)是否為開啟狀態(tài)  
  private boolean toggleStateOn;  
  //開關(guān)狀態(tài)的監(jiān)聽事件  
  private OnToggleStateListener toggleStateListener;  
  //記錄開關(guān)·當(dāng)前的狀態(tài)  
  private boolean isToggleStateListenerOn;  
  //手指按下屏幕時(shí)的x坐標(biāo)  
  private float proX;  
  //手指滑動(dòng)過程中當(dāng)前x坐標(biāo)  
  private float currentX;  
  //是否處于滑動(dòng)狀態(tài)  
  private boolean isSlipping;  
  //記錄上一次開關(guān)的狀態(tài)  
  private boolean proToggleState \= true;  
  //開關(guān)開啟時(shí)的矩形  
  private Rect rect\_on;  
  //開關(guān)關(guān)閉時(shí)的矩形  
  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:  
      //記錄手指按下時(shí)的x坐標(biāo)  
      proX \= event.getX();   
      currentX \= proX;  
      //將滑動(dòng)標(biāo)識(shí)設(shè)置為true  
      isSlipping \= true;  
      break;  
  
    case MotionEvent.ACTION\_MOVE:  
      //記錄手指滑動(dòng)過程中當(dāng)前x坐標(biāo)  
      currentX \= event.getX();  
      break;  
  
    case MotionEvent.ACTION\_UP:  
      //手指抬起時(shí)將是否滑動(dòng)的標(biāo)識(shí)設(shè)置為false  
      isSlipping \= false;  
      //處于關(guān)閉狀態(tài)  
      if(currentX < bkgSwitchOn.getWidth() / 2 ){  
        toggleStateOn \= false;  
      } else { // 處于開啟狀態(tài)  
        toggleStateOn \= true;  
      }  
        
      // 如果使用了開關(guān)監(jiān)聽器,同時(shí)開關(guān)的狀態(tài)發(fā)生了改變,這時(shí)使用該代碼  
      if(isToggleStateListenerOn && toggleStateOn != proToggleState){  
        proToggleState \= toggleStateOn;  
        toggleStateListener.onToggleState(toggleStateOn);  
      }  
      break;  
    }  
      
    invalidate();//重繪  
    return true;  
  }  
  
  @Override  
  protected void onDraw(Canvas canvas) {  
    super.onDraw(canvas);  
    //用來記錄我們滑動(dòng)塊的位置  
    int left\_slip \= 0;   
    Matrix matrix \= new Matrix();  
    Paint paint \= new Paint();  
    if(currentX < bkgSwitchOn.getWidth() / 2){  
      //在畫布上繪制出開關(guān)狀態(tài)為關(guān)閉時(shí)的  背景圖片  
      canvas.drawBitmap(bkgSwitchOff, matrix, paint);  
    }else{  
      //在畫布上繪制出開關(guān)狀態(tài)為開啟時(shí)的  背景圖片  
      canvas.drawBitmap(bkgSwitchOn, matrix, paint);  
    }  
    if(isSlipping){//開關(guān)是否處于滑動(dòng)狀態(tài)  
      // 滑動(dòng)塊 是否超過了整個(gè)滑動(dòng)按鈕的寬度   
      if(currentX \> bkgSwitchOn.getWidth()){  
        //指定滑動(dòng)塊的位置  
        left\_slip \= bkgSwitchOn.getWidth() \- btnSlip.getWidth();  
      } else {  
        //設(shè)置當(dāng)前滑動(dòng)塊的位置  
        left\_slip \= (int) (currentX \- btnSlip.getWidth() /2);  
      }  
    } else {//開關(guān)是否處于   不滑動(dòng)狀態(tài)   
      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);  
  }  
  //計(jì)算開關(guān)的寬高  
  @Override  
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
    setMeasuredDimension(bkgSwitchOn.getWidth(), bkgSwitchOn.getHeight());  
  }  
    
  /\*\*  
   \* 設(shè)置圖片資源信息  
   \* @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());  
  }  
  
  /\*\*  
   \* 設(shè)置開關(guān)按鈕的狀態(tài)  
   \* @param state  
   \*/  
  public void setToggleState(boolean state) {  
    toggleStateOn \= state;  
  }  
  
  /\*\*  
   \* 自定義開關(guān)狀態(tài)監(jiān)聽器  
   \* @author liuyazhuang  
   \*  
   \*/  
  interface OnToggleStateListener {  
    abstract void onToggleState(boolean state);  
  }  
  //設(shè)置開關(guān)監(jiān)聽器并將是否設(shè)置了開關(guān)監(jiān)聽器設(shè)置為true  
  public void setOnToggleStateListener(OnToggleStateListener listener) {  
    toggleStateListener \= listener;  
    isToggleStateListenerOn \= true;  
  }  
}

2、MainActivity

這個(gè)類實(shí)現(xiàn)很簡(jiǎn)單,主要的功能就是加載界面布局,初始化界面控件,調(diào)用MyToggle類中的方法實(shí)現(xiàn)按鈕的開關(guān)效果

具體代碼實(shí)現(xiàn)如下:

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 {  
    //自定義開關(guān)對(duì)象  
    private MyToggle toggle;  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity\_main);  
        toggle \= (MyToggle) findViewById(R.id.toggle);  
        //設(shè)置開關(guān)顯示所用的圖片  
        toggle.setImageRes(R.drawable.bkg\_switch, R.drawable.bkg\_switch, R.drawable.btn\_slip);  
        //設(shè)置開關(guān)的默認(rèn)狀態(tài)    true開啟狀態(tài)  
        toggle.setToggleState(true);  
        //設(shè)置開關(guān)的監(jiān)聽  
        toggle.setOnToggleStateListener(new OnToggleStateListener() {  
            @Override  
            public void onToggleState(boolean state) {  
                // TODO Auto-generated method stub  
                if(state){  
                    Toast.makeText(getApplicationContext(), "開關(guān)開啟", 0).show();  
                } else {  
                    Toast.makeText(getApplicationContext(), "開關(guān)關(guān)閉", 0).show();  
                }  
            }  
        });  
    }  
}

3、布局文件activity_main.xml

這里我引用了自己定義的View類MyToggle。

具體代碼實(shí)現(xiàn)如下:

<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\>

4、AndroidManifest.xml

具體代碼如下:

<?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\>

三、運(yùn)行效果

四、溫馨提示

大家可以到鏈接下載Android自定義開關(guān)按鈕實(shí)現(xiàn)示例完整源代碼

本實(shí)例中,為了方面,我把一些文字直接寫在了布局文件中和相關(guān)的類中,大家在真實(shí)的項(xiàng)目中要把這些文字寫在string.xml文件中,在外部引用這些資源,切記,這是作為一個(gè)Android程序員最基本的開發(fā)常識(shí)和規(guī)范,我在這里只是為了方便直接寫在了類和布局文件中。

到此這篇關(guān)于Android實(shí)現(xiàn)史上最簡(jiǎn)單自定義開關(guān)按鈕的文章就介紹到這了,更多相關(guān)Android自定義開關(guān)按鈕內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論