自定义控件按钮的滑动和点击+粘性

自定义控件的代码,需继承View

package com.example.zyzdy_kaiguan;

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

/**
 * 设置滑动效果
 * 1、 手指按下记录坐标
 * 2、来到新坐标记录下
 * 3、计算偏移量
 * 4、依据偏移量移动按钮
 * 5、屏蔽非法值
 * 6、重新初始化初始值
 */
public class MyView extends View implements View.OnClickListener {
    // true:开的状态 false:关闭状态(默认关闭状态)点击事件
    private boolean isOpened = false;
    // 画笔-辅助工具
    private Paint paint;
    // 背景图片
    private Bitmap backgroudbitmap;
    private Bitmap slidingbitmap;
    // 滑动按钮距离左边的距离
    private float sledingLeft;
    // 滑动按钮距离左边的最大距离
    private float maxLeft;

    /**
     * 自定义控件的构造方法--带样式
     */
    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

    /**
     * 系统规定,在布局文件使用View,实例化的时候只用带有两个参数的构造方法
     */
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    /**
     * 通常在代码中实例化的时候使用
     */
    public MyView(Context context) {
        super(context);
        initView();
    }

    /**
     * 初始化View
     */
    private void initView() {
        // 创建画笔
        paint = new Paint();
        // 设置抗锯齿
        paint.setAntiAlias(true);
        // 创建背景图片
        backgroudbitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.switch_background);
        slidingbitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.slide_button);
        // 滑动按钮距离左边的最大距离
        maxLeft = backgroudbitmap.getWidth() - slidingbitmap.getWidth();
        // 设置点击事件
        setOnClickListener(this);

    }

    /**
     * 执行的主要方法:
     * 1.构造
     * 2.测量-onMeasure();一般是View的时候测量
     * 3.指定view的大小和位置:onLayout();
     * 一般View用不到,但是如果当前View继承的是ViewGroup,一定要实现,有义务指定孩子的位置和大小。
     * 4.绘制-onDraw();
     * 5、onTouchEvent()
     */

    /**
     * 1.View本身大小多少,这由onMeasure()决定;
     * 2.View在ViewGroup中的位置如何,这由onLayout()决定
     * 3.绘制View,onDraw()定义了如何绘制这个View
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 指定大小
        setMeasuredDimension(backgroudbitmap.getWidth(),
                backgroudbitmap.getHeight());
    }

    /**
     * 绘制
     */
    @Override
    protected void onDraw(Canvas canvas) {
        // canvas.drawBitmap(bitmap, left, top, paint)左上坐标(从左上顶点开始画)
        canvas.drawBitmap(backgroudbitmap, 0, 0, paint);
        canvas.drawBitmap(slidingbitmap, sledingLeft, 0, paint);
    }

    // 起始的X轴的坐标
    private float startX;

    // 历史的X轴的坐标
    private float lastX;

    /**
     * 判断是点击事件还是触摸事件
     * true:点击事件生效触摸事件不生效 false:点击事件不生效,触摸事件生效
     */
    private boolean isClickEnbale = false;

    /**
     * 触摸事件
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:// 按下
                // 1.手指按下的坐标
                lastX = startX = event.getX();
                // 手指按下时,设置状态为点击事件生效,触摸事件不生效
                isClickEnbale = true;
                break;
            case MotionEvent.ACTION_MOVE:// 滑动
                // 2.来到新的坐标
                float newX = event.getX();

                // 3.计算偏移量
                float distanceX = newX - startX;

                // 从开始到现在滑动的距离
                //绝对值
                if (Math.abs(newX - lastX) > 5) {
                    // 如果偏移量大于5,设状态为点击事件失效,触摸事件生效
                    isClickEnbale = false;
                }
                // 重新绘制界面
                flunshView(distanceX);

                // 5.重新记录初始值
                startX = event.getX();

                break;

            case MotionEvent.ACTION_UP:// 离开
                // 如果触摸事件生效,点击事件失效
                if (!isClickEnbale) {
                    // 如果滑动按钮距离左边的距离大于滑动按钮距离左边最大距离的一半,就设置状态为开
                    if (sledingLeft > maxLeft / 2) {
                        isOpened = true;
                    } else if (sledingLeft <= maxLeft / 2) {
                        // 如果滑动按钮距离左边的距离小于滑动按钮距离左边最大距离的一半,就设置状态为关
                        isOpened = false;
                    }
                    // 重新绘制界面
                    flushViewState();

                }
                break;

            default:
                break;
        }
        return true;
    }

    /**
     * 屏蔽非法值和根据位置重新绘制
     */
    private void flunshView(float distanceX) {
        sledingLeft += distanceX;
        if (sledingLeft < 0) {
            sledingLeft = 0;
        }

        if (sledingLeft > maxLeft) {
            sledingLeft = maxLeft;
        }

        // 4.根据最新的位置绘制
        invalidate();
    }

    /**
     * 点击事件
     */
    @Override
    public void onClick(View v) {
        // 如果是点击状态生效,触摸事件失效
        if (isClickEnbale) {
            flushViewState();
            // 点击后,如果是状态时开的话就设置为关,如果是关的状态就设置为开
            isOpened = !isOpened;
        }
    }

    private void flushViewState() {
        // 开的状态
        if (isOpened) {
            // 开的状态
            sledingLeft = maxLeft;
        } else {
            // 关的状态
            sledingLeft = 0;
        }

        invalidate();// 在主线程中执行 导致onDraw执行
    }

}
主页面代码

package com.example.zyzidingyikongjiankaiguan;

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

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RelativeLayout RelativeLayout = findViewById(R.id.RelativeLayout);
        //实现自己定义的自定义控件
        MyView buttonView = new MyView(this);
        //调用按钮
        RelativeLayout.addView(buttonView);
    }
}

布局文件

xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/RelativeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <com.example.zyzidingyikongjiankaiguan.MyView
        android:id="@+id/bv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

RelativeLayout>

你可能感兴趣的:(自定义控件按钮的滑动和点击+粘性)