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

Android自定義控件之開關(guān)按鈕學(xué)習(xí)筆記分享

 更新時間:2016年05月19日 17:35:35   作者:TheMrNice  
這篇文章主要為大家分享了Android自定義開關(guān)按鈕的學(xué)習(xí)筆記,內(nèi)容豐富,具有一定的參考價值,感興趣的小伙伴們可以參考一下

今天來講講自定義單個控件,就拿開關(guān)按鈕來講講,相信大家見了非常多這樣的了,先看看效果:

我們可以看到一個很常見的開關(guān)按鈕,那就來分析分析。

首先:

這是由兩張圖片構(gòu)成:

①一張為有開和關(guān)的背景圖片

②一張為控制開和關(guān)的滑動按鈕

第一步:

寫個類繼承View,并重寫幾個方法:

第一個為構(gòu)造函數(shù),重寫一個參數(shù)的函數(shù)和兩個參數(shù)的函數(shù)就夠了,因為兩個參數(shù)的函數(shù)能夠使用自定義屬性

第二個為控制控件的大小–>protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {}

第三個為繪制控件的方法–>protected void onDraw(Canvas canvas) {}

第二步:

將用戶指定的兩張圖片加載進(jìn)來,這里使用自定義屬性加載, 在values目錄下新建attrs.xml,在xml文件中指定自定義屬性名和自定義屬性的字段及值類型(即背景圖和滑塊圖)即可:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="switchView_attrs">
    <attr name="background" format="reference"></attr>
    <attr name="slide" format="reference"></attr>
  </declare-styleable>  
</resources>

各個字段的含義我在這就不講了,不懂的就去看看前幾篇《Android開發(fā)筆記之自定義組合控件》有講過,寫好就只需在構(gòu)造函數(shù)中加載進(jìn)來

public SwitchView(Context context, AttributeSet attrs) {
    super(context, attrs);
    //拿到自定義屬性
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.switchView_attrs);
    //拿到自定義字段的值
    Drawable switchBackground = ta.getDrawable(R.styleable.switchView_attrs_background);
    Drawable switchView_slide = ta.getDrawable(R.styleable.switchView_attrs_slide);
    //把值設(shè)置到相應(yīng)組件上
    backgroundBitmap = convertDrawable2BitmapSimple(switchBackground);
    switchSlide = convertDrawable2BitmapSimple(switchView_slide);
  }

不過要注意的是:

因為從自定義屬性中取到的是Drawable對象,而我們要的是一個Bitmap對象,所以我們先得把Drawable對象轉(zhuǎn)成Bitmap對象,其實有很多種方法來轉(zhuǎn),這里就介紹種最簡單的方法,借助與BitmapDrawable類:

//將Drawable轉(zhuǎn)成Bitmap
  public Bitmap convertDrawable2BitmapSimple(Drawable drawable) {
    BitmapDrawable bd= (BitmapDrawable)drawable;
    return bd.getBitmap();
  }

第三步:

onMeasure方法來控制控件的大小,我們可以看到這個開關(guān)按鈕的大小就跟背景的大小一樣大,只需要設(shè)置為背景的大小:

//控制控件的大小
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (backgroundBitmap != null) {
      //控件大小設(shè)置為背景的大小
      setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
    }else {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
  }

第四步:

既然這個開關(guān)按鈕需要通過點擊或移動來控制控件的開和關(guān),所以就需要實現(xiàn)onTouchEvent方法,當(dāng)然應(yīng)該有三個事件會觸發(fā):按下、移動和抬起的時候,每次點擊、移動或抬起都需要重繪,我們先來分析下滑塊的狀態(tài)有哪些(應(yīng)該有四種狀態(tài))一開始默認(rèn)狀態(tài)為空:

1.點擊的時候
2.移動的時候
3.抬起的時候
4.空的時候(即什么都沒干的時候)

先分析下點擊的時候的情況:

①當(dāng)按下或移動的坐標(biāo)大于滑塊寬度一半時將滑塊右移

②當(dāng)按下或移動的坐標(biāo)小于滑塊寬度一半時滑塊不動

注:防止滑塊移至背景外面,最大是滑塊右邊和背景右邊對齊(即最大離左邊為背景寬度-滑塊寬度)

再來看看移動的時候的情況應(yīng)該是和點擊的時候是一樣的。

再來分析抬起的時候的情況:

①如果開關(guān)狀態(tài)是打開的就將滑塊移動至右邊

②如果開關(guān)狀態(tài)是關(guān)閉的就將滑塊移動至左邊

那怎么判斷什么時候是打開狀態(tài)和關(guān)閉狀態(tài)呢??

①抬起的坐標(biāo)大于背景寬度一半的時候設(shè)為打開狀態(tài)

②抬起的坐標(biāo)小于背景寬度坐標(biāo)一 半的時候設(shè)為關(guān)閉狀態(tài)

再來分析下空的時候,可以發(fā)現(xiàn)它和抬起的時候的情況是一樣的。

第五步:

在onDraw方法中將背景和滑塊繪制出來。剛才分析了onTouchEvent方法,這次是一樣的,滑塊的四個狀態(tài)分別處理,前面onTouchEvent方法中滑塊的狀態(tài)改變,然后通過invalidate()方法來通知系統(tǒng)重繪。

第六步:

我們做這個自定義控件是為了讓用戶使用的,現(xiàn)在這個是沒有什么用的,用戶用不了,所以可以通過設(shè)置監(jiān)聽器來對外提供接口。

/** 
   * switchView開關(guān)監(jiān)聽接口
   * 
   * */
  interface OnSwitchChangedListener {
    public void onSwitchChange(boolean isOpen);
  }
  /** 
   * 設(shè)置 switchView狀態(tài)監(jiān)聽 
   * */
  public void setOnChangeListener(OnSwitchChangedListener listener) {
    switchListener = listener;
  }

這個監(jiān)聽器中的boolean值需要賦值,那在什么時候賦值呢,應(yīng)該是在抬起或空的狀態(tài)的時候給它賦值,因為那個時候才真正確定開關(guān)按鈕是打開的還是關(guān)閉的。

第七步:

到這一步就是來使用了,在布局文件中把自定義的這個控件定義出來

<com.example.custom.SwitchView
    minguo:background="@drawable/switch_background"
    minguo:slide="@drawable/slide_button_background"
    android:id="@+id/switchView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>


使用定義好的View應(yīng)該都會用了,不會的去看看《android開發(fā)筆記之自定義組合控件》。

核心代碼:

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:minguo="http://schemas.android.com/apk/res/com.example.custom"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.example.custom.MainActivity" >
  <com.example.custom.SwitchView
    minguo:background="@drawable/switch_background"
    minguo:slide="@drawable/slide_button_background"
    android:id="@+id/switchView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
</LinearLayout>

自定義View: SwitchView.java

/**
 * 自定義開關(guān)按鈕
 * @author Administrator
 *
 */
public class SwitchView extends View {
  //背景圖片和滑塊圖片
  private Bitmap backgroundBitmap,switchSlide;
  //畫筆
  private Paint paint;
  //得到的x坐標(biāo)(點擊、移動、抬起)
  private float currentX;
  //判斷開關(guān)是否打開的標(biāo)記位
  private boolean isOpen = false;
  //開關(guān)打開與關(guān)閉的監(jiān)聽器
  private OnSwitchChangedListener switchListener;
  //滑塊的四種狀態(tài)
  public static final int STATE_DOWN = 1; //按下的時候
  public static final int STATE_MOVE = 2; //移動的時候
  public static final int STATE_UP = 3;  //抬起的時候
  public static final int STATE_NONE = 0; //空的時候(即什么都沒干的時候)
  //標(biāo)記狀態(tài)(默認(rèn)為空狀態(tài))
  private int state = STATE_NONE;
  public SwitchView(Context context) {
    super(context,null);
  }
  public SwitchView(Context context, AttributeSet attrs) {
    super(context, attrs);
    //拿到自定義屬性
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.switchView_attrs);
    //拿到自定義字段的值
    Drawable switchBackground = ta.getDrawable(R.styleable.switchView_attrs_background);
    Drawable switchView_slide = ta.getDrawable(R.styleable.switchView_attrs_slide);
    //把值設(shè)置到相應(yīng)組件上
    backgroundBitmap = convertDrawable2BitmapSimple(switchBackground);
    switchSlide = convertDrawable2BitmapSimple(switchView_slide);
  }
  //將Drawable轉(zhuǎn)成Bitmap
  public Bitmap convertDrawable2BitmapSimple(Drawable drawable) {
    BitmapDrawable bd = (BitmapDrawable)drawable;
    return bd.getBitmap();
  }
  //控制控件的大小
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (backgroundBitmap != null) {
      //控件大小設(shè)置為背景的大小
      setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
    }else {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
  }
  //繪制控件的樣式
  @Override
  protected void onDraw(Canvas canvas) {
    //背景為空的時候才將背景繪制
    if (backgroundBitmap != null) {
      paint = new Paint();
      //第一個參數(shù)表示需要畫的Bitmap
      //第二個參數(shù)表示Bitmap左邊離控件的左邊距
      //第三個參數(shù)表示Bitmap上邊離控件的上邊距
      //第四個參數(shù)表示畫筆
      canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
    }
    switch (state) {
    case STATE_DOWN:    //按下和移動的觸發(fā)事件都一樣,都是將滑塊移動
    case STATE_MOVE:
      //當(dāng)按下或移動的坐標(biāo)大于滑塊寬度一半時將滑塊右移
      if (currentX > switchSlide.getWidth()/2f) {
        //讓滑塊向右滑動(重新繪制滑塊的位置)
        float left = currentX - switchSlide.getWidth()/2f;
        //防止滑塊移至背景外面,最大是滑塊右邊和背景右邊對齊(即最大離左邊為背景寬度-滑塊寬度)
        float maxLeft = backgroundBitmap.getWidth() - switchSlide.getWidth();
        if (left > maxLeft) {
          left = maxLeft;
        }
        canvas.drawBitmap(switchSlide, left, 0, paint);
      //當(dāng)按下或移動的坐標(biāo)小于滑塊寬度一半時滑塊不動
      }else if (currentX < switchSlide.getWidth()/2f) {
        //讓滑塊不動就可以了
        canvas.drawBitmap(switchSlide, 0, 0, paint);
      }
      break;
    case STATE_NONE:    //空或抬起的時候?qū)⒒瑝K至于左邊或右邊
    case STATE_UP:
      //如果是打開的將滑塊移動至右邊,并將打開狀態(tài)傳至監(jiān)聽器
      if (isOpen) {
        if (switchListener != null) {
          switchListener.onSwitchChange(true);
        }
        canvas.drawBitmap(switchSlide, 
            backgroundBitmap.getWidth() - switchSlide.getWidth(), 0, paint);
      //如果是關(guān)閉的將滑塊至于左邊,并將關(guān)閉狀態(tài)傳至監(jiān)聽器
      }else {
        if (switchListener != null) {
          switchListener.onSwitchChange(false);
        }
        canvas.drawBitmap(switchSlide, 0, 0, paint);
      }
      break;
    default:
      break;
    }
  }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      currentX = event.getX();
      //將標(biāo)記位修改成按下的狀態(tài)
      state = STATE_DOWN;
      //通知系統(tǒng)重新繪制界面
      invalidate();//在主線程
//     postInvalidate();//在子線程
      break;
    case MotionEvent.ACTION_MOVE:
      currentX = event.getX();
      //將標(biāo)記位修改為移動狀態(tài)
      state = STATE_MOVE;
      invalidate();
      break;
    case MotionEvent.ACTION_UP:
      currentX = event.getX();
      //將標(biāo)記為修改為抬起狀態(tài)
      state = STATE_UP;
      //抬起的坐標(biāo)大于背景寬度一半的時候設(shè)為打開狀態(tài)
      if (currentX > backgroundBitmap.getWidth()/2f) {
        //滑塊在右邊,開啟
        isOpen = true;
      //抬起的坐標(biāo)小于背景寬度坐標(biāo)一 半的時候設(shè)為關(guān)閉狀態(tài)
      }else if (currentX < backgroundBitmap.getWidth()) {
        //滑塊在左邊,關(guān)閉
        isOpen = false;

      }
      invalidate();
      break;
    }
    return true;
  }
  /** 
   * switchView開關(guān)監(jiān)聽接口
   * 
   * */
  interface OnSwitchChangedListener {
    public void onSwitchChange(boolean isOpen);
  }
  /** 
   * 設(shè)置 switchView狀態(tài)監(jiān)聽 
   * */
  public void setOnChangeListener(OnSwitchChangedListener listener) {
    switchListener = listener;
  }
}

MainActivity.java

public class MainActivity extends Activity {

  private SwitchView switchView;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    switchView = (SwitchView) findViewById(R.id.switchView);
    switchView.setOnChangeListener(new OnSwitchChangedListener() {
      @Override
      public void onSwitchChange(boolean isOpen) {
        if (isOpen) {
          //打開開關(guān)的時候的邏輯
          Toast.makeText(MainActivity.this, "開關(guān)打開了", Toast.LENGTH_LONG).show();
        }else {
          //關(guān)閉開關(guān)的時候的邏輯
          Toast.makeText(MainActivity.this, "開關(guān)關(guān)閉了", Toast.LENGTH_LONG).show();
        }
      }
    });
  }
}

大家看起來這么簡單的一個寫了這么多,其實我們學(xué)習(xí)這個不是為了寫這個,比這個好的開源多的是,而是為了學(xué)習(xí)這種思路與思維,大家趕緊試試吧!

謝謝大家的閱讀,也希望大家可以繼續(xù)關(guān)注腳本之家的更多精彩內(nèi)容。

相關(guān)文章

  • Android 攝像頭高斯模糊的示例代碼

    Android 攝像頭高斯模糊的示例代碼

    本篇文章主要介紹了Android 攝像頭高斯模糊的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • Android自定義View仿支付寶芝麻信用分儀表盤

    Android自定義View仿支付寶芝麻信用分儀表盤

    前幾天支付寶剛剛升級到v9.9,看了一眼里面的芝麻信用分,儀表盤挺好看的,所以想著來寫一個這個版本的儀表盤,不說完全一模一樣,只是為了猜測支付寶在做這個的時候是如何設(shè)計的,在此記錄一下,有需要的可以參考借鑒。
    2016-09-09
  • Android控件之GridView用法實例分析

    Android控件之GridView用法實例分析

    這篇文章主要介紹了Android控件之GridView用法,通過繪制九宮格的實例形式分析了GridView可滾動網(wǎng)格的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-09-09
  • http請求繞過Filter的實現(xiàn)實例

    http請求繞過Filter的實現(xiàn)實例

    這篇文章主要介紹了http請求繞過Filter的實現(xiàn)實例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Android視圖綁定方法深入探究

    Android視圖綁定方法深入探究

    這篇文章主要介紹了Android視圖綁定方法,通過視圖綁定viewBinding功能,您可以更輕松地編寫可與視圖交互的代碼。在模塊中啟用視圖綁定之后,系統(tǒng)會為該模塊中的每個XML
    2023-01-01
  • Android Activity之間的數(shù)據(jù)傳遞方法總結(jié)

    Android Activity之間的數(shù)據(jù)傳遞方法總結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于Android Activity之間的數(shù)據(jù)傳遞方法,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • 使用Composing?builds提升Android編譯速度

    使用Composing?builds提升Android編譯速度

    這篇文章主要介紹了使用Composing?builds提升Android編譯速度示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Android 中 viewpager 滑動指示器的實例代碼

    Android 中 viewpager 滑動指示器的實例代碼

    本文通過實例代碼給大家介紹了android 中 viewpager 滑動指示器,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-12-12
  • Android編程之在SD卡上進(jìn)行文件讀寫操作實例詳解

    Android編程之在SD卡上進(jìn)行文件讀寫操作實例詳解

    這篇文章主要介紹了Android編程之在SD卡上進(jìn)行文件讀寫操作的方法,結(jié)合實例形式較為詳細(xì)的分析了Android的文件操作及針對SD卡的存取操作相關(guān)技巧,需要的朋友可以參考下
    2015-12-12
  • Android倒計時的開始與停止 剩余時分秒的展示

    Android倒計時的開始與停止 剩余時分秒的展示

    這篇文章主要為大家詳細(xì)介紹了Android倒計時的開始與停止,剩余時分秒的展示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09

最新評論