Android 自定义view的实现 滑动按钮案列

Android自定义view的实现 滑动按钮案列

在我们安卓中经常用到一些控件,很多都是系统提供的,我们有时候会觉得这些控件很挫,而且有时候这些控件不能实现我们所需要的功能,这是我们就可以自定义一个view,然后在我们的布局文件中使用,由于是自定义的控件,所以我们对于它的操作就更加会符合我们的要求。
我们来看一下效果图:
Android 自定义view的实现 滑动按钮案列_第1张图片

首先我们来看一看我们的布局文件:





    

可以看到我们的布局文件非常简单,也非常奇怪。我们通常写的控件都是
下面我们就来实现我们的MyToggleButton类

package com.lxt.administrator.myview;

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.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Administrator on 2016/4/22 0022.
 */
public class MyToggleButton extends View implements View.OnClickListener {
    private Bitmap background;
    private Bitmap togglebutton;
    private Paint paint;
    private int marginleft=0;
    private boolean currState=false;
    private  boolean isDrag=false;
    public MyToggleButton(Context context) {
        super(context);
    }

    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init(){
        //获取到要用的图片资源
        background= BitmapFactory.decodeResource(getResources(),R.drawable.switch_background);
        togglebutton=BitmapFactory.decodeResource(getResources(),R.drawable.slide_button);
        paint=new Paint();
        paint.setAntiAlias(true);//打开抗锯齿
        setOnClickListener(this);
    }
    /**
     * 自定义View显示在屏幕上you有几个重要步骤
     * 1:构造方法创建对象,要用两个参数的那个
     * 2:测量view的大小,onMersure(int,int);
     *3:确定view的位置 onLayout
     * 4:绘制view的内容 onDraw()
     * */

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //设置view的大小
        setMeasuredDimension(background.getWidth(),background.getHeight());
    }
//确定位置的时候调用此方法,但是还是要有父布局来决定
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
/**
 * 将两个图片绘制出来
 *0,0图片的左边界,图片的上边界
 */

        canvas.drawBitmap(background,0,0,paint);

        canvas.drawBitmap(togglebutton,marginleft,0,paint);
    }

    @Override
    public void onClick(View v) {
		/*
		 * 如果没有拖动,才执行改变状态的动作
		 */
        if(!isDrag){
            currState = !currState;
            flushstate();
        }
    }

    //判断是否发生拖动,如果拖动则响应滑动事件,否则响应点击事件
    /**
     * down 事件时的x值
     */
    /**
     * touch 事件的上一个x值
     */
    public int lastX;
    public int firstX;
    private int dis;
    @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;
                }
                dis= (int) (event.getX()-lastX);
                lastX= (int) event.getX();
                marginleft=marginleft+dis;
                break;
            case MotionEvent.ACTION_UP:

                //在发生拖动的情况下,根据最后的位置,判断当前开关的状态
                if (isDrag) {

                    int maxLeft = background.getWidth() - togglebutton.getWidth(); // slideBtn
                    // 左边届最大值
				/*
				 * 根据 slideBtn_left 判断,当前应是什么状态
				 */
                    if (marginleft > maxLeft / 2) { // 此时应为 打开的状态
                        currState = true;
                    } else {
                        currState = false;
                    }

                    flushstate();
                }
                break;
        }

        flushView();

        return true;
    }
    /**
     * 实现滑动效果
     */


    private void flushstate(){
        if(currState){
            //
            marginleft=background.getWidth()-togglebutton.getWidth();
        }else{
            marginleft=0;
        }
        flushView();
    }
    private void  flushView(){
        /**
         * 判断这个按钮距离左边的最大值,不能出了范围
         * 0<=marginleft <=  maxLeft
         */
        int max=background.getWidth()-togglebutton.getWidth();
        marginleft=(marginleft>0)?marginleft:0;
        marginleft=(marginleft

首先我们会发现我们的类继承了View这个类,这是我们自定义view的第一步,紧接着我们的编译器会报错,提示我们需要重写它的构造方法我们会发现一共有说三个构造方法,那么我们究竟使用哪一个呢?我们先来看一些我们只重写第一个方法会有什么反应。
E/AndroidRuntime: FATAL EXCEPTION: main
                                                                            Process: com.lxt.administrator.myview, PID: 2607
                                                                            java.lang.RuntimeException: Unable to start activity ComponentInfo{com.lxt.administrator.myview/com.lxt.administrator.myview.MainActivity}: android.view.InflateException: Binary XML file line #12: Binary XML file line #12: Error inflating class com.lxt.administrator.myview.MyToggleButton
                                                                                at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                                                                                at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                                                                                at android.app.ActivityThread.-wrap11(ActivityThread.java)
                                                                                at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
                                                                                at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                at android.os.Looper.loop(Looper.java:148)
                                                                                at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                                                                             Caused by: android.view.InflateException: Binary XML file line #12: Binary XML file line #12: Error inflating class com.lxt.administrator.myview.MyToggleButton



我们会发现我们运行程序的时候会报错。其实多出来的这个参数AttributeSet是用来接受我们定义在布局文件中的属性信息的这个参数很重要,没有他我们无法加载我们的自定义view,即使不是自定义view也是用这个参数来实现获取我们布局文件中的参数的。如果小伙伴不相信可以将调用AttributeSet里面的方法来将它打印出来看看。
我们这个案列需要用到两张图片一张作为我们的背景图片,一张作为我们的可以滑动的图片。我们需要从我们的构造方法中将我们需要的一些资源初始化。要想获取我们在drawable中的图片我们可以通过
 background= BitmapFactory.decodeResource(getResources(),R.drawable.switch_background);
来获取,同时我们也要初始化我们的画笔paint.我们的功能是点击的时候,按钮跳到另一边,滑动的时候跟着滑动的距离而改变。所以我们要给我们 的view添加一个点击事件。我们实现自定义view一般都要实现一下几个方法才可以创造出我们自己的view
自定义View显示在屏幕上you有几个重要步骤
* 1:构造方法创建对象,要用两个参数的那个
* 2:测量view的大小,onMersure(int,int);
* 3:确定view的位置 onLayout
* 4:绘制view的内容 onDraw()
首先第一步我们已经实现了。紧接着我们要实现我们的第二个onMersure()方法。这个方法是用来确定我们的自定义的view的大小也就是宽和高。
我们可以通过这个方法来实现设置我们的view的宽和高
setMeasuredDimension(background.getWidth(), background.getHeight());
紧接着我们要确定我们的view的位置,这个方法大家可以不用去关心,主要是去确定我们view在我们父布局中的位置,有一个建议权,但是最终决定还是我们的父布局。
最后一个我们方法onDraw()就是来画出我们的view
canvas.drawBitmap(background, 0, 0, paint);

canvas.drawBitmap(togglebutton, marginleft, 0, paint);
在这里我们将我们的两张图片画出来。里面有四个参数,第一个参数是我们要画的图片,第二个是我们的图片的左边距和上边距的坐标,这里我们的背景图片当然是覆盖上去。我们的可滑动按钮顶部也是紧挨着我们的画布,但是他的左边距是一个变量因为他要随着我们的点击或者滑动而变化。下面我们先实现我们的点击按钮来实现按钮的移动。其实道理很简单,就是当我们点击按钮的时候我们来判断当前我们的按钮距离我们的左边距的距离,如果为0说明我们的按钮目前处于关的状态我们只需要将它的左边距变大,让他能够将它的背景图片开显示出来。这时候我们确定一个滑动按钮距离左边距的最大距离
int maxLeft = background.getWidth() - togglebutton.getWidth();
这是我们就确定了我们的按钮距离左边距的两个关键距离0,maxLeft。当我们为开的时候我们的左边距为maxLeft,当我们为关的状态是,我们的左边距是0。紧接着我们要调用
invalidate();
来刷新我们的页面。这样我们就实现了点击按钮的功能。
当然我们不仅仅是要实现点击功能我们还要实现滑动功能。道理都是一样,通过改变滑动图片的左边距值来改变我们的活动图片的位置。我们需要重写我们的onTouchEvent()方法。用来记录我们的手指滑动的距离。这里头我加了一个判断就是如果手指滑动的距离小于5,我们默认为点击事件,否则才会被认为是滑动事件。当我们的滑动按钮距离左边距的距离大于最大距离的一半的时候,我们认为当前的状态是开的状态,将当前状态设为开,否则为关。然后在在下面的flushstate()里面判断现在的状态,如果为开的状态,就将滑动图片的左边距设置为最大左边距。关的状态时将我们滑动按钮的左边距设置为0,。这两个值也就是我们一开始说的两个最重要的值。最后在还是调用invalidate()方法刷新一下界面。这样我们级实现了我们的自定义view的滑动按钮。



你可能感兴趣的:(Android)