Android自定义控件之ToggleButton

来源:互联网 发布:睡眠时间 知乎 编辑:程序博客网 时间:2024/05/17 03:08

View的绘制流程

measure(): 测量,用来控制控件的大小,final 不建议复写
layout(): 布局,用来控制控件摆放的位置
draw(): 绘制,用来控制控件的样子
如果需要自定义view

onMeasure():
onLayout():
onDraw():
行为控制:(触摸)

dispatchTouchEvent(): (View和ViewGroup)分发touch,android希望开发者在这个方法中实现touch的传递
onInterceptTouchEvent(): (ViewGroup) 拦截touch事件,android希望开发者在这个方法中通过父容器来控制是否拦截孩子的touch
onTouchEvent(): (View和ViewGroup) 当用户触摸控件时候的回调,Android希望开发者在这个方法中实现行为

view.setOnTouchListener();

View的绘制刷新: invalidate()触发view的刷新–>draw()—>onDraw()
View的布局刷新 requestLayout()触发重新布局–>layout()—>onLayout()–>draw()—>onDraw()

这里写图片描述
这里写图片描述

public class SlideToggleView extends View {    private final static int STATE_DOWN = 0;    private final static int STATE_MOVE = 1;    private final static int STATE_UP = 2;    private Bitmap mBackground;// 滑动的背景    private Bitmap mSlideImage;// 滑动块的图片    private Paint paint = new Paint();    private boolean isOpened = false;// 用来标记控件是否是打开的    private float mCurrentX;    private int mState = STATE_UP;// 用来记录用户当前手势的状态,默认状态    private OnToggleListener mListener;    public SlideToggleView(Context context) {        this(context, null);    }    public SlideToggleView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public void setSlideBackground(int resId) {        mBackground = BitmapFactory.decodeResource(getResources(), resId);    }    public void setSlideImage(int resId) {        mSlideImage = BitmapFactory.decodeResource(getResources(), resId);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // 设置 当前控件的实际的宽高        if (mBackground != null) {            int measuredWidth = mBackground.getWidth();            int measuredHeight = mBackground.getHeight();            setMeasuredDimension(measuredWidth, measuredHeight);        } else {            super.onMeasure(widthMeasureSpec, heightMeasureSpec);        }    }    @Override    protected void onDraw(Canvas canvas) {        // 画背景        if (mBackground != null) {            // canvas 画布,画板            int left = 0;            int top = 0;            canvas.drawBitmap(mBackground, left, top, paint);        }        // 画滑动块        if (mSlideImage == null) {            return;        }        // 当控件在左侧-->关闭情况        // 如果用户手指按下时,当前的点的水平坐标在 滑动块的左侧,就不动        // canvas.drawBitmap(mSlideImage, 0, 0, paint);        int slideWidth = mSlideImage.getWidth();        int backWidth = mBackground.getWidth();        switch (mState) {        case STATE_DOWN:        case STATE_MOVE:            if (!isOpened) {                // 当控件在左侧-->关闭情况                if (mCurrentX < slideWidth / 2f) {// 当前的点的水平坐标在 滑动块的左侧                    canvas.drawBitmap(mSlideImage, 0, 0, paint);                } else {                    // 在右侧                    float left = mCurrentX - slideWidth / 2f;                    float maxLeft = backWidth - slideWidth;                    if (left > maxLeft) {                        left = maxLeft;                    }                    canvas.drawBitmap(mSlideImage, left, 0, paint);                }            } else {                // 在右侧--》打开的                // 当前的点的水平坐标在 滑动块的右侧,不动                if (mCurrentX > backWidth - slideWidth / 2f) {                    // 画打开的状态                    float left = backWidth - slideWidth;                    canvas.drawBitmap(mSlideImage, left, 0, paint);                } else {                    //                    float left = mCurrentX - slideWidth / 2f;                    if (left < 0) {                        left = 0;                    }                    canvas.drawBitmap(mSlideImage, left, 0, paint);                }            }            break;        case STATE_UP:            if (isOpened) {                // 打开的                float left = backWidth - slideWidth;                canvas.drawBitmap(mSlideImage, left, 0, paint);            } else {                // 关闭的                canvas.drawBitmap(mSlideImage, 0, 0, paint);            }            break;        default:            break;        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        // MotionEvent--->用户触摸时的实时数据        int action = event.getAction();        switch (action) {        case MotionEvent.ACTION_DOWN:            // 按下时            // 改变状态            mState = STATE_DOWN;            mCurrentX = event.getX();            break;        case MotionEvent.ACTION_MOVE:            // 移动            mState = STATE_MOVE;            mCurrentX = event.getX();            break;        case MotionEvent.ACTION_UP:            // 手指抬起            mState = STATE_UP;            mCurrentX = event.getX();            int width = mBackground.getWidth();            if (mCurrentX > width / 2f && !isOpened) {                // 打开                isOpened = true;                if (mListener != null) {                    mListener.onToggleChanged(this, true);                }            } else if (mCurrentX <= width / 2f && isOpened) {                // 关闭                isOpened = false;                if (mListener != null) {                    mListener.onToggleChanged(this, false);                }            }            break;        default:            break;        }        invalidate();        // 是否出处理touch事件        return true;// 消费掉所有的touch行为    }    public void setOnToggleListener(OnToggleListener listener) {        this.mListener = listener;    }    public interface OnToggleListener {        // 暴露当前是否是打开或是关闭的状态,提供数据给调用者        void onToggleChanged(SlideToggleView view, boolean isOpened);    }}
public class MainActivity extends Activity {    private SlideToggleView mToggleView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mToggleView = (SlideToggleView) findViewById(R.id.stv);        // 设置资源        mToggleView.setSlideBackground(R.drawable.switch_background);        mToggleView.setSlideImage(R.drawable.slide_button_background);        mToggleView.setOnToggleListener(new OnToggleListener() {            public void onToggleChanged(SlideToggleView view, boolean isOpened) {                Toast.makeText(MainActivity.this, isOpened ? "打开" : "关闭",                        Toast.LENGTH_SHORT).show();                         }        });    }}

参考:Android自定义控件