自定义开关控件

简单自定义控件,实现按钮开关,继承View

效果图:



触摸事件

    优先执行

点击事件

声明自定义属性

步骤1  

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="com.example.mhy.zidingyiview.MyToggle">
        <attr name="slide_state" format="boolean" />
        <!--reference代表该属性为引用类型 -->
        <attr name="slide_drawable" format="reference" />
    </declare-styleable>
</resources>


步骤2   使用属性


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myattr="http://schemas.android.com/apk/res/com.example.mhy.zidingyiview"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mhy.zidingyiview.MainActivity">

    <com.example.mhy.zidingyiview.MyToggle
        myattr:slide_state="true"
        myattr:slide_drawable="@mipmap/slide_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:id="@+id/mcb" />
</RelativeLayout>


步骤3  

//在布局文件中调用(没有自定义属性)
    public MyToggle(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();

        //加载自定义属性
        flag = attrs.getAttributeBooleanValue(
                "http://schemas.android.com/apk/res/com.example.mhy.zidingyiview",
                "slide_state", false);
        /*第一个参数是自定义属性的命名空间
          第二个参数为自定义属性的名字
          第三个参数为如果未获取到自定义属性的值,给该变量返回的默认值
         */
        int id = attrs.getAttributeResourceValue(
                "http://schemas.android.com/apk/res/com.example.mhy.zidingyiview",
                "slide_drawable", 0);
        if(id!=0){
            slide = BitmapFactory.decodeResource(getResources(), id);
        }
        flushState();
    }

完整代码:

values下的attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="com.example.mhy.zidingyiview.MyToggle">
        <attr name="slide_state" format="boolean" />
        <!--reference代表该属性为引用类型 -->
        <attr name="slide_drawable" format="reference" />
    </declare-styleable>
</resources>
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myattr="http://schemas.android.com/apk/res/com.example.mhy.zidingyiview"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mhy.zidingyiview.MainActivity">

    <com.example.mhy.zidingyiview.MyToggle
        myattr:slide_state="true"
        myattr:slide_drawable="@mipmap/slide_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:id="@+id/mcb" />
</RelativeLayout>

MainActivity.java

package com.example.mhy.zidingyiview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private MyToggle mcb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mcb = (MyToggle) findViewById(R.id.mcb);
        mcb.setListener(new MyToggle.OnStateChangedListener() {

            @Override
            public void change(boolean isOpen) {
                if (isOpen) {
                    Toast.makeText(getApplicationContext(), "当前的状态为开", 0)
                            .show();
                } else {
                    Toast.makeText(getApplicationContext(), "当前的状态为关", 0)
                            .show();
                }
            }
        });
    }
}

MyToggle.java

package com.example.mhy.zidingyiview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by mhy on 2016/6/12.
 */
public class MyToggle extends View {

    private Bitmap bg;
    private Bitmap slide;


    /**
     * 记录控件开关状态
     */
    private boolean flag = false;
    private int max_distance;
    //滑块距离父控件左边的距离
    private int slide_left;

    //在自定义文件中使用(使用了自定义属性)
    public <span style="color:#ff6666;"><strong>MyToggle</strong></span>(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    //一般代码中调用
    public <span style="color:#ff0000;"><strong>MyToggle</strong></span>(Context context) {
        super(context);
        initView();
    }

    //在布局文件中调用(没有自定义属性)
    public <span style="color:#ff6666;"><strong>MyToggle</strong></span>(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();

        //加载自定义属性
        flag = attrs.getAttributeBooleanValue(
                "http://schemas.android.com/apk/res/com.example.mhy.zidingyiview",
                "slide_state", false);
        /*第一个参数是自定义属性的命名空间
          第二个参数为自定义属性的名字
          第三个参数为如果未获取到自定义属性的值,给该变量返回的默认值
         */
        int id = attrs.getAttributeResourceValue(
                "http://schemas.android.com/apk/res/com.example.mhy.zidingyiview",
                "slide_drawable", 0);
        if(id!=0){
            slide = BitmapFactory.decodeResource(getResources(), id);
        }
        flushState();
    }

    private void initView() {
        bg = BitmapFactory.decodeResource(getResources(),
                R.mipmap.switch_background);
        slide = BitmapFactory.decodeResource(getResources(),
                R.mipmap.slide_button);
        max_distance = bg.getWidth() - slide.getWidth();
        //设置条目的点击事件
        setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //修改滑块的状态
                if (isClick) {
                    if (flag) {
                        flag = false;
                    } else {
                        flag = true;
                    }
                    //刷新界面
                    flushState();
                }
            }
        });
    }

    // 回调方法
    private OnStateChangedListener listener;

    // 可以设置接口
    public void setListener(OnStateChangedListener listener) {
        this.listener = listener;
    }

    // 定义了接口
    public interface O<span style="color:#ff0000;"><strong>nStateChangedListener</strong></span> {
        void change(boolean isOpen);
    }

    private int startX;
    private boolean isClick = true;// 是否允许响应点击事件

    //触摸事件
    int distance;//记录总共滑动的距离

    @Override
    public boolean <span style="color:#ff0000;"><strong>onTouchEvent</strong></span>(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://按下的操作
                //步骤1 记录开始的位置
                startX = (int) event.getX();
                System.out.println("ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:// 手指移动调用
                System.out.println("ACTION_MOVE");
                // 步骤2 记录新的位置
                int newX = (int) event.getX();
                // 步骤3 记录坐标的改变
                int dx = newX - startX;
                distance += Math.abs(dx);
                // 步骤4 修改位置
                slide_left += dx;
                // invalidate();
                flushView();
                // 步骤5
                startX = newX;
                break;
            case MotionEvent.ACTION_UP:
                if (Math.abs(distance) > 20) { // 如果发现滑动的总距离 大于20像素 认为处理了触摸事件
                    // 不要处理点击事件
                    isClick = false;//屏蔽了点击
                    distance = 0; // 重置滑动总距离
                }
                 // 如果点击事件能执行 不会执行触摸事件 如果触摸事件执行 就不会执行点击事件
                if(!isClick) {
                    System.out.println("ACTION_UP");
                    if (slide_left > max_distance / 2) {
                        flag = true;
                    } else {
                        flag = false;
                    }
                    flushState();
                }
                break;
            default:
                break;
        }
        //由系统处理是滑动还是点击
        return super.onTouchEvent(event);
    }

    public void flushView() {
        // 坐标修正
        if (slide_left < 0) {
            slide_left = 0;
        } else if (slide_left > max_distance) {
            slide_left = max_distance;
        }
        invalidate();
    }

    private void flushState() {
        if (flag) {
            slide_left = max_distance;
        } else {
            slide_left = 0;
        }
        if (listener != null) {
            listener.change(flag);// 把当前的选中状态 赋值给接口
        }
        invalidate(); //刷新界面 重新调用onDraw方法
    }

    //测量控件的大小 onMeasure 在onDraw方法前调用 用来测量控件的宽和高
    @Override
    protected void <span style="color:#ff6666;"><strong>onMeasure</strong></span>(int widthMeasureSpec, int heightMeasure) {
        setMeasuredDimension(bg.getWidth(), bg.getHeight());//测量当前控件的宽和高
    }

    @Override
    protected void <span style="color:#ff6666;"><strong>onDraw</strong></span>(Canvas canvas) {
        //Paint paint = new Paint();
        //paint.setColor(Color.RED);
        canvas.drawBitmap(bg, 0, 0, null);
        canvas.drawBitmap(slide, slide_left, 0, null);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值