Android自定義滑動開關按鈕


一、效果圖

二、主要技術點

  1.自定義View

  2.自定義屬性

三、自定義控件的步驟

  1.自定義類繼承自View或View的子類;

  2.重寫構造方法

    (1)MyView(Context);  // 在代碼中new 對象時調用此方法 

    (2)MyView(Context,AttributeSet);  // 在XML布局文件中聲明此View,創建對象時,由系統自動調用

    (3)MyView(Context,AttributeSet,int);  // 與方法2用法一樣,只是多了一個參數:默認樣式

  3.重寫相關方法,實現我們的需求,一般要重寫的方法:

    (1)onMeasure(int,int);  // 系統測量控件大小時調用該方法 

    (2)onLayout(boolean,int,int,int,int);  // 系統為該view 指定位置時調用此方法,子view的位置,自身只有建議權,決定權在父view的手中。一般不需要重寫。

    (3)onDraw(Canvas);  // 為本view繪制內容時,調用該方法。

四、為新控件添加自定義屬性的步驟:

  1.在attrs.xml文件中聲明屬性,有屬性名(name)和格式(format)。如 

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- 聲明屬性集的名稱 -->
    <declare-styleable name="MyToggleBtn">
        <!-- 聲名一個屬性  name是my_background   類型為 引用類型      引用資源ID -->
        <attr name="my_background" format="reference" />
        <!-- 聲名一個屬性  name是my_slide_btn   類型為 引用類型      引用資源ID -->
        <attr name="my_slide_btn" format="reference" />
        <!-- 聲名一個屬性  name是curr_state   類型為 boolean 類型 -->
        <attr name="curr_state" format="boolean" />
    </declare-styleable>

</resources>

 

  2.在布局文件中使用新屬性,使用之前必須先聲明命名空間,如xmlns:gnnuit="http://schemas.android.com/apk/res/com.gnnuit.togglebutton",其中“http://schemas.android.com/apk/res/”為Android固定的格式,“com.gnnuit.togglebutton”為應用程序的包名,與AndroidManifest.xml聲明的包名一樣。

<com.gnnuit.togglebutton.MyToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        gnnuit:curr_state="true"
        gnnuit:my_background="@drawable/switch_background"
        gnnuit:my_slide_btn="@drawable/slide_button" />

 

  3.在自定義View的構造方法中,通過解析AttributeSet對象,獲得所需要的屬性值。

四。核心代碼

package com.gnnuit.togglebutton;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyToggleButton extends View implements android.view.View.OnClickListener {
    private Bitmap backgroundBitmap;// 背景圖片
    private Bitmap slideButtonBitmap;// 滑動按鈕圖片
    private Paint paint;
    private boolean currentState = false;// 當前狀態
    private float left_slide;// 滑動按鈕的左邊界位置
    private float startX, lastX;// 記錄滑動按鈕滑動時的開始和結束位置
    private boolean isSlide = false;// 記錄是否移動滑動按鈕
    private float dist;

    /**
     * 在布局文件中聲明此View,創建時由系統自動調用該構造方法
     * 
     * @param context
     * @param attrs
     */
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 獲取自定義屬性
        currentState = attrs.getAttributeBooleanValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "curr_state", false);
        
        int backgroundResourceId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "my_background", -1);
        if (backgroundResourceId == -1) {
            throw new RuntimeException("請設置背景圖片");
        }
        backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundResourceId);
        
        int slideBtnResourceId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "my_slide_btn", -1);
        if (slideBtnResourceId == -1) {
            throw new RuntimeException("請設置背景圖片");
        }
        slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideBtnResourceId);

        if (currentState) {
            left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
        }
        initView();// 初始化
    }

    /**
     * 初始化
     */
    private void initView() {
        // 初始化圖片
        // backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
        // slideButtonBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
        // 初始化畫筆
        paint = new Paint();
        paint.setAntiAlias(true);// 設置抗鋸齒
        // 設置點擊事件
        setOnClickListener(this);
    }

    @Override
    /**
     * 測量尺寸的回調方法
     */
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());// 設置控件的寬和高,單位是像素
    }

    @Override
    /**
     * 繪制當前View的內容
     */
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
        canvas.drawBitmap(slideButtonBitmap, left_slide, 0, paint);
    }

    @Override
    public void onClick(View v) {
        if (!isSlide) {
            currentState = !currentState;
            flushState();// 刷新界面
        }
    }

    /**
     * 刷新當前狀態
     */
    private void flushState() {
        if (currentState) {
            left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
        } else {
            left_slide = 0;
        }
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isSlide = false;
            startX = lastX = event.getX();
            break;

        case MotionEvent.ACTION_MOVE:
            lastX = event.getX();
            dist = lastX - startX;
            if (Math.abs(dist) > 5) {
                isSlide = true;
                left_slide += dist;
                flushShow();
                startX = event.getX();
            }
            break;
        case MotionEvent.ACTION_UP:
            if (isSlide) {
                if (left_slide > (backgroundBitmap.getWidth() - slideButtonBitmap.getWidth()) / 2) {
                    left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
                    currentState = true;
                } else {
                    left_slide = 0;
                    currentState = false;
                }
                flushShow();
            }
            break;
        }
        return true;
    }

    /**
     * 刷新當前View
     */
    private void flushShow() {
        int maxLeftSlide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
        // left_slide的范圍為0=<left_slide<=maxLeftSlide
        if (left_slide > maxLeftSlide) {
            left_slide = maxLeftSlide;
            currentState = true;
        } else if (left_slide < 0) {
            left_slide = 0;
            currentState = false;
        }
        invalidate();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM