自定义开关控件(ToggleView)继承View实现

package yuan.jxau.cn.toggleview.view;

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;

import yuan.jxau.cn.toggleview.R;

/**
 * Created by 编程只服JAVA on 2016.11.26.
 */

/**
 * 自定义开关
 *
 * Android界面绘制流程
 * 测量       摆放    绘制
 * measure->layout->draw
 *    |        |      |
 * onMeasure->onLayout->onDraw  重写这些方法,实现自定义控件
 *
 * onResume()方法之后执行
 *
 * View
 * onMeasure()(在这个方法里面指定自己的宽高)->onDraw()(绘制自己的内容)
 *
 * ViewGroup
 * onMeasure(指定自己的宽高,所有子view的宽高)()->onLayout()(摆放所有子view)->onDraw()(绘制内容)
 */
public class ToggleView extends View {
    private Bitmap switchBackgroud;
    private Bitmap slideBackground;
    private Boolean switchState;
    private Paint paint;
    private float currentX;
    private Boolean isTouchMode = false;
    private OnSwitchStateUpdateListener onSwitchStateUpdateListener;

    /**
     * 用于代码创建控件
     * @param context
     */
    public ToggleView(Context context) {
        super(context);
        init();
    }

    private void init() {
        paint = new Paint();
    }

    /**
     * 用于在xml里使用,可指定自定义属性
     * @param context
     * @param attrs
     */
    public ToggleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        String namespace = "http://schemas.android.com/apk/res-auto";
        int switchResouceBackground = attrs.getAttributeResourceValue(namespace ,"switch_background", R.drawable.switch_background);
        int slideResouceBackGround = attrs.getAttributeResourceValue(namespace , "slide_button" , R.drawable.slide_button);
        Boolean isOpen = attrs.getAttributeBooleanValue(namespace,"switch_state",false);

        setSlideBackgroundResource(slideResouceBackGround);
        setSwitchBackgroundResource(switchResouceBackground);
        setState(isOpen);
    }

    /**
     * 用于在xml里使用,可指定自定义属性,如果指定了样式,则走此构造函数
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public ToggleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //重写测量方法
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(switchBackgroud.getWidth(),switchBackgroud.getHeight());
    }

    //重写绘制方法
    @Override
    protected void onDraw(Canvas canvas) {
        //1.绘制背景
        canvas.drawBitmap(switchBackgroud,0,0,paint);
        //2.绘制滑块
        if (isTouchMode){
            //用户触摸状态
            float newLeft = currentX - slideBackground.getWidth()/2.0f;

            /**
             * 限定滑块滑动范围
             */
            int maxLeft = switchBackgroud.getWidth() - slideBackground.getWidth();
            if(newLeft < 0){
                newLeft = 0;
            }else if (newLeft > maxLeft){
                newLeft = maxLeft;
            }
            //根据当前用户触摸到的位置绘制滑块
            canvas.drawBitmap(slideBackground, newLeft , 0,paint);
        }else{
            if (switchState){
                //打开状态
                int newLeft = switchBackgroud.getWidth() - slideBackground.getWidth();
                canvas.drawBitmap(slideBackground,newLeft,0,paint);
            }else {
                //关闭状态
                canvas.drawBitmap(slideBackground,0,0,paint);
            }
        }
    }

    //重写触摸事件,响应用户的触摸
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN :
                currentX = event.getX();
                isTouchMode = true;
                break;
            case MotionEvent.ACTION_MOVE :
                currentX = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                isTouchMode = false;
                currentX = event.getX();

                float center = switchBackgroud.getWidth()/2.0f;
                Boolean state = currentX >center;

                /**
                 * 如果ToggleView的状态发生改变,通知外面ToggleView的状态已经发生了变化
                 */
                if (state != switchState && onSwitchStateUpdateListener != null){
                    onSwitchStateUpdateListener.onStateUpdate(state);
                }

                switchState = state;
                break;
        }

        //#######重绘界面,onDraw()被调用,里面的变量会重新生效,界面会更新########
        invalidate();

        return true;//返回true:消费了用户的触摸事件
    }

    /**
     * 设置背景图片
     * @param switch_background
     */
    public void setSwitchBackgroundResource(int switch_background) {
        switchBackgroud = BitmapFactory.decodeResource(getResources(), switch_background);
    }

    /**
     * 设置滑块的背景图片
     * @param slide_button
     */
    public void setSlideBackgroundResource(int slide_button) {
       slideBackground = BitmapFactory.decodeResource(getResources(), slide_button);
    }

    public void setState(boolean switchState) {
        //状态回调,将当前状态传出去
        this.switchState = switchState;
    }

    //状态变化的监听方法,当ToggleView的状态发生改变的时候,会通知外面。
    public void setOnSwitchStateUpdateListener(OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
        this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
    }

    public interface OnSwitchStateUpdateListener{
        void onStateUpdate(Boolean state);
    }
}

自定义属性attrs.xml



    
        
        
        
    
布局文件




    



你可能感兴趣的:(android)