android 防IOS开关SwitchButton

项目重用到了IOS风格的一个开关SwitchButton,网上也找了蛮多,但是文件都比较大,所以自己写了一个。

先看效果图

android 防IOS开关SwitchButton

github:https://github.com/xiebinJava/SwitchButton

 

下面直接上代码:

 

package com.xie.brad.myswitchbutton.MyButton;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.xie.brad.myswitchbutton.R;

import java.util.Date;

/**
 * Created by dell on 2017/10/20.
 */

public class SwitchButton extends View {


    private Paint paint;
    private float downX;
    private float moveX;
    private float BTmoveX;
    private float dx;
    private float maxX;
    private boolean isOpen;
    private Date date;
    private long downTime;
    private long upTime;
    private int mWidth;
    private int mHeight;
    private int sRight;
    private float sBottom;
    private float sLeft;
    private int sTop;
    private float sWidth;
    private float sHeight;
    private float sCenterX;
    private float sCenterY;
    private Path sPath = new Path();
    private int bLeft;
    private int bTop;
    private float bBottom;
    private float bRight;
    private float bWidth;
    private float bRadius;
    private float bStrokWidth;
    private float sScale;
    private float sScaleCenterX;
    private OnSwitchListener switchListener;
    private boolean firstState;

    public SwitchButton(Context context) {
        super(context, null);

    }

    public SwitchButton(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        paint = new Paint();
        date = new Date();
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwitchButton);
        firstState = typedArray.getBoolean(R.styleable.SwitchButton_switch_state, false);
        isOpen = firstState;
    }

    public SwitchButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    // height = width * 0.65 左右
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = (int) (widthSize * 0.65f);
        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w; // 视图自身宽度
        mHeight = h; // 视图自身高度
        sLeft = sTop = 0; // 田径场 左和上的坐标
        sRight = mWidth; // 田径场 右占自身的全部
        sBottom = mHeight * 0.8f; // 田径场底部 占全身的百分之八十, 下面预留百分之二十的空间画按钮阴影。
        sWidth = sRight - sLeft; // 田径场的宽度
        sHeight = sBottom - sTop; // 田径场的高度
        sCenterX = (sRight + sLeft) / 2; // 田径场的X轴中心坐标
        sCenterY = (sBottom + sTop) / 2; // 田径场的Y轴中心坐标
        RectF sRectF = new RectF(sLeft, sTop, sBottom, sBottom);
        sPath.arcTo(sRectF, 90, 180);
        sRectF.left = sRight - sBottom;
        sRectF.right = sRight;
        sPath.arcTo(sRectF, 270, 180);
        sPath.close();    // path准备田径场的路径
        bLeft = bTop = 0;
        bRight = bBottom = sBottom; // 和田径场同高,同宽的节奏, 没错包裹圆形的肯定是个正方形是小孩子都知道的。
        bWidth = bRight - bLeft;
        final float halfHeightOfS = (sBottom - sTop) / 2;
        bRadius = halfHeightOfS * 0.9f; // 按钮的半径
        bStrokWidth = 2 * (halfHeightOfS - bRadius); // 按钮的边框
        sScale = 1 - bStrokWidth / sHeight; //替换之前的0.98<
        sScaleCenterX = sWidth - halfHeightOfS;
        if (isOpen){
            BTmoveX = sWidth - bWidth / 2;
        }else {
            BTmoveX = bWidth / 2;
        }
        maxX = sWidth - bWidth;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        if (isOpen) {
            paint.setColor(getResources().getColor(R.color.colorPrimary));
        } else {
            paint.setColor(0xffcccccc);
        }
        canvas.drawPath(sPath, paint); // 画出田径场
        canvas.save();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(getResources().getColor(R.color.colorAccent));
        canvas.drawCircle(BTmoveX, bWidth / 2, bRadius, paint); // 按钮白底
        canvas.restore();
        paint.reset();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downTime = date.getTime();
                firstState = isOpen;
                break;
            case MotionEvent.ACTION_MOVE:
                moveX = event.getX();
                dx = moveX - downX;
                if (!isOpen) {
                    if (dx < 0) {
                        BTmoveX = bWidth / 2;
                        isOpen = false;
                    } else if (dx > maxX) {
                        BTmoveX = maxX + (bWidth / 2);
                        isOpen = true;
                    } else {
                        BTmoveX = dx + (bWidth / 2);
                    }
                } else {
                    if (dx > 0) {
                        BTmoveX = maxX + bWidth / 2;
                        isOpen = true;
                    } else if (Math.abs(dx) > maxX) {
                        BTmoveX = bWidth / 2;
                        isOpen = false;
                    } else {
                        BTmoveX = maxX - Math.abs(dx) + (bWidth / 2);
                    }
                }
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                upTime = date.getTime();
                if (Math.abs(dx) < 3 && upTime - downTime < 1000) {
                    if (isOpen) {
                        isOpen = false;
                        BTmoveX = bWidth / 2;
                        firstState = false;
                        switchListener.closebutton();
                    } else {
                        isOpen = true;
                        BTmoveX = maxX + bWidth / 2;
                        firstState = true;
                        switchListener.openbutton();
                    }
                } else {
                    if (!isOpen) {
                        if (dx < maxX / 2) {
                            BTmoveX = bWidth / 2;
                            isOpen = false;
                        } else {
                            BTmoveX = maxX + bWidth / 2;
                            isOpen = true;
                            firstState = true;
                            switchListener.openbutton();
                        }
                    } else {
                        if (Math.abs(dx) < maxX / 2 || dx > maxX / 2) {
                            BTmoveX = maxX + bWidth / 2;
                            isOpen = true;
                        } else {
                            BTmoveX = bWidth / 2;
                            isOpen = false;
                            firstState = false;
                            switchListener.closebutton();
                        }
                    }
                }
                if (firstState){
                    if (!isOpen){
                        switchListener.closebutton();
                    }
                }else {
                    if (isOpen){
                        switchListener.openbutton();
                    }
                }
                invalidate();
                break;
        }
        return true;
    }


    public void setOnSwitchListener(OnSwitchListener onSwitchListener) {
        this.switchListener = onSwitchListener;
    }

    public interface OnSwitchListener {
        void openbutton();

        void closebutton();
    }


}

 

用法:

  <com.xie.brad.myswitchbutton.MyButton.SwitchButton
                android:id="@+id/switchbutton"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                app:switch_state="true"/>

 

package com.xie.brad.myswitchbutton;

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

import com.xie.brad.myswitchbutton.MyButton.SwitchButton;

public class MainActivity extends AppCompatActivity implements SwitchButton.OnSwitchListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SwitchButton switchButton = (SwitchButton) findViewById(R.id.switchbutton);
        switchButton.setOnSwitchListener(this);
    }

    @Override
    public void openbutton() {
        Toast.makeText(this,"开",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void closebutton() {
        Toast.makeText(this,"关",Toast.LENGTH_SHORT).show();
    }
}

代码写的蛮久了,最近闲暇,拿出来分享,代码比较乱,希望大家提出意见

上一篇:递归tree结构的数据(修改antd tree结构的数据)


下一篇:NG-ZORRO-MOBILE (Ant Design Mobile of Angular) 移动端UI组件库正式发布