view对象显示在屏幕上,有几个重要步骤:
1.构造方法创建对象
2.测量view的大小 onMeasure(int,int)
3.确定view的位置,view自身有一些建议权,决定权在父view手中 onLayout()
4.绘制view的内容 onDraw(canvas)
第一步:需要准备2张图片
(1)创建一个类,MyButton,并继承自view
(2)这个时候会需要你实现个构造方法。
public MyButton(Context context) //这个构造方法是在代码中生成需要的
public MyButton(Context context, AttributeSet attrs) //这个在布局文件中声明的view,创建时系统自动调用。
在这个方法中初始化图片switchBackground = BitmapFactory.decodeResource(getResource(),R.mipmap.背景图片);slideBtn = BitmapFactory.decodeResource(getResource(),R.mipmap.按钮);创建画笔paint = new Paint();paint.setAntiAlias(true); //打开抗锯齿使用onMeasure方法:并使用setMeasuredDimension(switchBackground.getWidth,switchBackground.getHeight);参数1:view的宽度 参数2:view的高度
(3)使用onDraw()方法(按钮中最重要的就是canvas.drawBitmap(slideButton,重要参数,0,paint))绘制背景canvas.drawBitmap(switchBackground,0,0,paint);绘制可滑动的按钮canvas.drawBitmap(slideButton,0,0,paint);参数1: 要绘制的图片参数2: 图片的左边界参数3: 图片的上边界参数4: 绘制图片要使用的画笔这个时候可以打开就会发现图片已经可以显示。第二步:实现按钮点击效果(1)创建一个变量private float slideBtn_left;canvas.drawBitmap(slideButton,slideBtn_left,0,paint);(2)onclick中设置点击后的变化设置一个变量:当前状态 true是打开 false是关闭
private boolean currstate = false;之后在onclick中设置点击后变量变化:currstate = !currstate;创建一个方法:刷新状态flushState()里面放置的内容:if(currstate){slideBtn_left = switchBackground.getWidth() - slideButton.getWidth();}else{ slideBtn_left = 0;}invalidate(); //刷新当前view 会导致onDraw方法的执行这样就完成了点击的效果了。第三步:滑动的效果,就贴代码了。主要就是那个 slideBtn_left这个参数的变化/** * Created by qichen on 2017/1/28. */ public class MytoggleButton extends View implements View.OnClickListener { /** * 作为背景图片 */ private Bitmap switchBackgroud; /** * 可以滑动的图片 */ private Bitmap slideButton; private Paint paint; /** * 滑动按钮的左边界,默认状态下是0 */ private float slideBtn_left; /** * 在代码里创建对象的时候,使用此构造方法 * @param context */ public MytoggleButton(Context context) { super(context); } /** * 在布局文件中声明的view,创建时由系统自动调用 * @param context * @param attrs */ public MytoggleButton(Context context, AttributeSet attrs) { super(context, attrs); initView(); } /** * 初始化 */ private void initView() { //初始化图片 switchBackgroud = BitmapFactory.decodeResource(getResources(), R.mipmap.switch_background); slideButton = BitmapFactory.decodeResource(getResources(), R.mipmap.slide_button); //初始化画笔 paint = new Paint(); paint.setAntiAlias(true);//打开抗锯齿 //添加onclick setOnClickListener(this); } /** * view 对象显示的屏幕上,有几个重要步骤: * 1.构造方法创建对象 * 2.测量view 的大小 onMeasure(int,int) * 3.确定view 的位置,view自身有一些建议权,决定权在父view手中 onLayout() * 4.绘制view 的内容,onDraw(canvas) */ /** * 测量尺寸时的回调方法 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // super.onMeasure(widthMeasureSpec, heightMeasureSpec); /** * 设置当前view的大小 * width : view的宽度 * height: view的高度 */ setMeasuredDimension(switchBackgroud.getWidth(),switchBackgroud.getHeight()); } /** * 确定位置的时候调用此方法 * 自定义view的时候,作用不大 */ // @Override // protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // super.onLayout(changed, left, top, right, bottom); // } /** * 当前开关的状态 * true 是打开状态 */ private boolean currstate = false; /** * 绘制当前view的内容 */ @Override protected void onDraw(Canvas canvas) { // super.onDraw(canvas); //绘制背景 /** * backgroundBitmap 要绘制的图片 * left 图片的左边界 * top 图片的上边界 * paint 绘制图片要使用的画笔 */ canvas.drawBitmap(switchBackgroud,0,0,paint); //绘制可滑动的按钮 左上角值 canvas.drawBitmap(slideButton,slideBtn_left,0,paint); } /** * 判断是否发生了拖动 * 如果拖动了,就不再相应onclick事件 */ private boolean isDrag = false; /** * onclick 事件在View.onToutchEvent 中被解析 * 系统对onclick 事件解析,过于简陋,只要有down事件 和 up事件,系统即认为发生了 onclick事件 */ @Override public void onClick(View view) { /** * 如果没有拖动,才执行改变状态的动作 */ if(!isDrag){ currstate = !currstate; flushState(); } } /** * 刷新当前状态 */ private void flushState() { if(currstate){ slideBtn_left = switchBackgroud.getWidth() - slideButton.getWidth(); }else{ slideBtn_left = 0; } //刷新当前view 回导致 onDraw 方法的执行 invalidate(); } /** * down 事件时的x值 */ private int firstX; /** * touch 事件的上一个x值 */ private int lastX; @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: firstX = lastX = (int) event.getX(); isDrag = false; break; case MotionEvent.ACTION_MOVE: //判断是否发生拖动 if(Math.abs(event.getX() - firstX) > 5){ isDrag = true; } //计算手指在屏幕上移动的距离 int dis = (int) (event.getX() - lastX); //将本次的位置 设置给lastX lastX = (int) event.getX(); //根据手指移动的距离,改变slideBtn_left 的值 slideBtn_left = slideBtn_left + dis; break; case MotionEvent.ACTION_UP: //在发生拖动的情况下,根据最后的位置,判断当前开关的状态 if(isDrag){ int maxLeft = switchBackgroud.getWidth() - slideButton.getWidth(); /** * 根据 slideBtn_left 判断,当前应是什么状态 */ if(slideBtn_left > maxLeft/2){ //此时应为打开的状态 currstate = true; }else{ currstate = false; } flushState(); } break; } flushView(); return true; } /** * 刷新当前视图 */ private void flushView() { /** * 对 slideBtn_left 的值进行判断,确保其在合理的位置 * * 0 <= slideBtn_left <= maxLeft */ // slideBtn 左边界最大值 int maxLeft = switchBackgroud.getWidth() - slideButton.getWidth(); //确保slideBtn_left >= 0 slideBtn_left = (slideBtn_left > 0) ? slideBtn_left :0; //确保 slideBtn_left <= maxLeft slideBtn_left = (slideBtn_left < maxLeft) ? slideBtn_left : maxLeft; invalidate(); } }