Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Andriod下完全自定義控件和在自定義控件中使用自定義屬性

Andriod下完全自定義控件和在自定義控件中使用自定義屬性

編輯:關於Android編程

首先,自定義控件分為三類:

自定義的組合控件

繼承View的自定義控件

繼承ViewGroup的自定義控件

在這裡,我要寫的是第二種,也就是繼承自View的自定義控件,第一種自定義的組合控件,我已經寫過了,可以在我的博客中可以找到

現在來看一下繼承View的自定義控件

首先,需要寫一個類繼承自View,那麼,它也有三個構造方法,有一個參數的構造方法實在代碼中new這個自定義控件時被調用;有兩個參數的構造方法是在布局中使用這個自定義控件的時候調用,有三個參數的構造方法,實在使用到這個自定義控件的樣式時被調用;同樣,用到那個就重寫那個

其次,需要重寫onMeasure()方法和onDraw()方法

onMeasure()方法是為了測量控件自己的寬高,onDraw()方法是為了繪制的內容,如果你繼承的是ViewGroup,那麼你還需要重寫onLayout()方法

最後,實現業務邏輯

在這裡,我實現的是一個開關的效果

如下圖:

 

這裡寫圖片描述

 

這是可以滑動和點擊的

自定義屬性的步驟,具體請參考我的自定義的組合控件,哪裡已經做了詳細說明

1、先自定義一個類繼承View

    // 在代碼中創建控件
    public MyButton(Context context) {
        super(context);
    }

    // 控件使用在xml布局文件中
    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    // 使用樣式時
    public MyButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

接下來,你需要在布局中使用這個控件,用全類名



    

2、重寫onMeasure()方法

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //把背景圖片的寬高作為控件的寬高
        setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight());
    }

3、重寫onDraw()方法

@Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);
        canvas.drawBitmap(mSwitchBackground, 0, 0, null);
        if(!isTouching){
            //根據當前狀態滑動圖片
            int left = 0;
            if(currentToggleState){ //如果是打開狀態,左邊距等於背景的寬度-滑塊的寬度
                left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
            }else {
                //關閉狀態
                left = 0;
            }
            canvas.drawBitmap(mSlideButton, left, 0, null);
        }else{
            //根據手指觸摸的位置,繪制滑動的圖片
            int left = currentX - mSlideButton.getWidth() / 2;      //為了讓用戶感覺手在圖片中間滑動
            if(left < 0){  //圖片超出左邊界,直接繪制到0位置
                left = 0;
            }else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){  //圖片超出右邊界,直接繪制到右邊
                left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
            }
            canvas.drawBitmap(mSlideButton, left, 0, null);
        }

    }

接下來就是處理自己的業務邏輯
在這裡,我把代碼全部放在這裡了,這是MyButton .java

 public class MyButton extends View {

    private Bitmap mSwitchBackground;
    private Bitmap mSlideButton;
    private boolean currentToggleState;  //記錄當前開關的狀態
    private int currentX;
    private boolean isTouching  = false; //記錄當前控件是否處於觸摸中
    private MyButtonOnStateChangedListener listener;

    private String namespace = "http://schemas.android.com/apk/res/com.abc.togglestate";

    /**
     * 在代碼中創建控件調用
     * @param context,
     */
    public MyButton(Context context) {
        super(context);

    }

    /**
     * 控件使用在xml布局中使用
     * @param context
     * @param attrs
     */
    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        //獲取布局文件中的屬性
        int backgroundRes = attrs.getAttributeResourceValue(namespace, "backgroundRes",0);
        setBackgroundRes(backgroundRes);

        int slideButtonRes = attrs.getAttributeResourceValue(namespace, "slideButtonRes", 0);
        setSlidButtonBackgroundRes(slideButtonRes);

        currentToggleState = attrs.getAttributeBooleanValue(namespace, "state", false);

    }

    /**
     * 使用樣式時調用
     * @param context
     * @param attrs
     * @param defStyle
     */
    public MyButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }

    /**
     * 測量自己的寬高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //把背景圖片的寬高作為控件的寬高
        setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight());
    }

    /**
     * 繪制內容
     */
    @Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);
        canvas.drawBitmap(mSwitchBackground, 0, 0, null);
        if(!isTouching){
            //根據當前狀態滑動圖片
            int left = 0;
            if(currentToggleState){ //如果是打開狀態,左邊距等於背景的寬度-滑塊的寬度
                left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
            }else {
                //關閉狀態
                left = 0;
            }
            canvas.drawBitmap(mSlideButton, left, 0, null);
        }else{
            //根據手指觸摸的位置,繪制滑動的圖片
            int left = currentX - mSlideButton.getWidth() / 2;      //為了讓用戶感覺手在圖片中間滑動
            if(left < 0){  //圖片超出左邊界,直接繪制到0位置
                left = 0;
            }else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){  //圖片超出右邊界,直接繪制到右邊
                left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
            }
            canvas.drawBitmap(mSlideButton, left, 0, null);
        }

    }

    /**
     * 給控件設置背景圖片
     * @param switchBackground
     */
    public void setBackgroundRes(int switchBackground) {
    mSwitchBackground = BitmapFactory.decodeResource(getResources(),switchBackground);
    }

    /**
     * 給控件設置滑塊
     * @param slideButtonBackground
     */
    public void setSlidButtonBackgroundRes(int slideButtonBackground) {
        mSlideButton = BitmapFactory.decodeResource(getResources(), slideButtonBackground);
    }

    /**
     * 開關的狀態(這裡沒有用到)
     * 用於外部調用
     * @param toggleState
     */
    public void isState(boolean toggleState) {
        currentToggleState = toggleState;
    }

    /**
     * 處理觸摸事件
     * 觸摸後,獲取當前的觸摸位置,根據位置,更新控件
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isTouching = true;
            currentX = (int) event.getX();
            break;

        case MotionEvent.ACTION_MOVE:
            currentX = (int) event.getX();
            break;
        case MotionEvent.ACTION_UP:
            isTouching = false;
            currentX = (int) event.getX();

            //手抬起後,更改當前控件的狀態,根據當前手觸摸的 位置和背景圖片的中間值進行比較
            boolean tempState = currentX >= mSwitchBackground.getWidth() / 2;
            //6.3、判斷當前的狀態是否發生變化
            if(tempState != currentToggleState){
                currentToggleState = tempState;
                if(listener != null){
                    listener.OnStateChanged(currentToggleState);
                }
            }
            break;
        }
        invalidate();  //重新繪制控件,自動觸發onDraw(在主線程中繪制控件)
        //postInvalidate();  //重新繪制控件,自動觸發onDraw(在子線程中繪制控件)
        return true;  //自己消費事件
    }

    //6.1、對外提供開關監聽
    public interface MyButtonOnStateChangedListener{
        public void OnStateChanged(boolean state);
    }

    //6.2、讓外界把監聽器傳進來
    public void setMyButtonOnStateChangedListener(MyButtonOnStateChangedListener listener){
        this.listener = listener;
    }
}

MainActivity.java代碼如下

public class MainActivity extends Activity {

    private MyButton mybutton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mybutton = (MyButton) findViewById(R.id.mybutton);
        mybutton.setMyButtonOnStateChangedListener(new MyButtonOnStateChangedListener() {

            @Override
            public void OnStateChanged(boolean state) {
                //出來開關狀態業務發生變化
                Toast.makeText(getApplicationContext(), "" + state, 0).show();
            }
        });
    }
}

希望能對看到這篇博客的小伙伴有所幫助,僅供大家參考

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved