自定义滑动开关按钮


继承已有View实现自定义View
主要步骤:
1.自定义类继承View 构造方法(注意每个的作用)
2.重写onMeasure方法,指定控件大小 测量view的大小 onMeasure方法
3.确定view的位置,view自身有一些建议权,决定权在父view手中. onLayuot();
4.重写onDraw方法,绘制控件的内容 onDraw方法
5.重写onTouchEvent方法,对touch事件进行解析 onTouchEvent方法

当监听了onTouchEvent与onClick方法时,滑动控件也会执行onClick方法,所以需要对这个进行处理:
处理方式见代码:就是在控件上滑动的时候定义个标记,让执行onClick方法的时候判断这个标记

使用到的图片如下:

效果:将右边这图作为左边按钮的背景图片

 

显示的功能:既可以点击也可以滑动

MainActivity.java :只是用来显示界面

MyButton.java  :监听事件都在本类,没有和MainActivity相关联(缺陷)

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;

public class MyButton extends View implements OnClickListener{
    
    private Bitmap backgroundBitmap;//开关的背景图片
    private Bitmap slideBtn;//可以滑动的图片
    private Paint paint;//画笔,用来画图片
    //滑动按钮在画布上的左边界,也就是根据滑动按钮的在画布上的位置来做出开与关的效果
    private float slideBtn_left;
    private boolean currentstart=false;//滑动按钮的当前状态,false为关,true为开

    /**
     * 在代码里面创建对象的时候,调用此构造方法
     */
    public MyButton(Context context) {
        super(context);
    }
    /**
     * 在布局文件中声明的view,创建时由系统自动调用此构造方法
     * @param context
     * @param attrs
     */
    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        //初始化图片
        backgroundBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
        slideBtn=BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
        //初始化画笔
        paint=new Paint();
        paint.setAntiAlias(true);//打开抗锯齿
        
        //为该视图设置监听事件
        setOnClickListener(this);
    }
    
    /**
     * 测量尺寸时的回调方法
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //设置当前view的大小     确定下面onDraw方法中画布的大小,所以这里不管布局文件中怎么设置长宽,这里都设置为了背景图片的宽高
        setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());
    }
    
    
    /**
     * 自定义view的时候,作用不大,确定位置的时候调用此方法
     */
    @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) {
        //画出backgroundBitmap这个图片,(0,0)代表在这个画布的左上角开始画
        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
        /*绘制 可滑动的按钮,   在画布上的坐标为:(slideBtn_left, 0)=(X,Y)
         * 即:当slideBtn_left等于0的时候,按钮的左上角就在画布的左上角位置,就把开挡住了,显示当前为关的状态
         * 当slideBtn_left=背景图片的宽-按钮的宽 ,代表按钮的左上角位置画在画布的(slideBtn_left, 0)
         */
        canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);
    }
    @Override
    public void onClick(View v) {
        if(!ismove){//如果之前没拖动,就执行单击事件
            if(currentstart){//
                slideBtn_left=0;
            }else{
                slideBtn_left=backgroundBitmap.getWidth()-slideBtn.getWidth();
            }
            System.out.println("响应onClick事件");
            currentstart=!currentstart;
            invalidate();//刷新视图,会调用onDraw方法
        }
    }
    
    
    //实现滑动的效果
    private int moveX;//记录移动后的位置,因为有时候移动一次停一下(没松开)再继续移动
    private int firstX;//记录第一次按下的位置
    private boolean ismove=false;//之前是否拖动了,false表示没拖动
    //onTouchEvent执行后会执行onClick方法,所以需要一个标记,来确定执不执行单击事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);//不调用就会把onClick屏蔽掉
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://按下
            firstX=moveX=(int) event.getX();
            ismove=false;//复位,使得下一次可以判断,必须在此复位
            break;
        case MotionEvent.ACTION_MOVE://移动
            int move=(int) event.getX()-moveX;//移动的距离
            slideBtn_left=slideBtn_left+move;
            moveX=(int) event.getX();//将移动的一次的位置记录下来
            if(slideBtn_left>backgroundBitmap.getWidth()-slideBtn.getWidth()){
                slideBtn_left=backgroundBitmap.getWidth()-slideBtn.getWidth();
            }else if(slideBtn_left<0){
                slideBtn_left=0;
            }
            ismove=true;//标记为拖动了,所以松开的时候只会执行触摸的UP事件,不会去执行单击事件,因为在单击事件中进行了判断
            break;
        case MotionEvent.ACTION_UP://抬起
            if(ismove){//如果拖动了就执行触摸事件
                if(event.getX()<backgroundBitmap.getWidth()/2){
                    slideBtn_left=0;//因为图片这个位置是关,  注意这里的event.getX是手指抬起的那点的坐标
                    currentstart=false;//标记为关的状态
                }else{
                    slideBtn_left=backgroundBitmap.getWidth()-slideBtn.getWidth();
                    currentstart=true;//标记为开的状态
                }
                System.out.println("响应onTouchEvent事件");
                break;
            }
        }
        invalidate();//刷新视图
        return true;
    }
}

布局文件activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <!-- 因为继承了View,所以可以使用View的所有属性,所以就可以使用下面的属性 -->
    <com.example.zdykg.MyButton
        android:id="@+id/my_but"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>

</RelativeLayout>

效果如下:

 

系统的滑动控件:Switch

Android 自定义 Switch 控件外观 (缺陷,不能控制宽高)

比较灵活的第三方滑动控件:

https://github.com/kyleduo/SwitchButton

使用可参考:https://www.cnblogs.com/tianzhijiexian/p/4231509.html

设置监听

 

posted @ 2016-07-30 14:46  ts-android  阅读(493)  评论(0编辑  收藏  举报