Android 自定义实现开关按钮

在开发我们经常会使用到自定义实现控件, 今天呢就跟大家说一说switch开关按钮的自定义实现。

为了大家的方便,直接把代码贴出来,不想那么麻烦自己去写的朋友可以直接copy到你们的项目中使用哦,颜色、大小都可以根据自己的需求改一改就行啦!

下面呢就是整个自定义类的代码:


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Looper;
import android.os.Parcelable;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

public class SlideSwitcher extends View {

    public static final int SHAPE_RECT = 1;
    public static final int SHAPE_CIRCLE = 2;
    private static final int RIM_SIZE = 4;
    private static final int DEFAULT_OPEN_COLOR = 0xFFC80000;
    private static final int DEFAULT_CLOSE_COLOR = 0xFFD0D0D0;
    
    // 4 attributes
    private int openColor;
    private int closeColor;
    private boolean isOpen;
    private int shape;

    // varials of drawing
    private Paint paint;
    private Rect backRect;
    private Rect frontRect;
    private RectF frontCircleRect;
    private RectF backCircleRect;
    private int alpha;
    private int maxLeft;
    private int minLeft;
    private int frontRectLeft;
    private int frontRectLeftBegin = RIM_SIZE;
    private int eventStartX;
    private int eventLastX;
    private int diffX = 0;
    private boolean slideable = true;
    private SlideListener mSlideListener;

    public interface SlideListener {
        void onStatusChanged(SlideSwitcher view, boolean isOpen);
    }

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

        paint = new Paint();
        paint.setAntiAlias(true);

        openColor = DEFAULT_OPEN_COLOR;
        closeColor = DEFAULT_CLOSE_COLOR;
        isOpen = false;
        shape = SHAPE_CIRCLE;
    }

    public SlideSwitcher(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlideSwitcher(Context context) {
        this(context, null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = measureDimension(280, widthMeasureSpec);
        int height = measureDimension(140, heightMeasureSpec);
        if (shape == SHAPE_CIRCLE) {
            if (width < height) width = height * 2;
        }
        setMeasuredDimension(width, height);
        initDrawingVal();
    }

    private void initDrawingVal() {
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        backCircleRect = new RectF();
        frontCircleRect = new RectF();
        frontRect = new Rect();
        backRect = new Rect(0, 0, width, height);
        minLeft = RIM_SIZE;
        if (shape == SHAPE_RECT)
            maxLeft = width / 2;
        else
            maxLeft = width - (height - 2 * RIM_SIZE) - RIM_SIZE;
        if (isOpen) {
            frontRectLeft = maxLeft;
            alpha = 255;
        } else {
            frontRectLeft = RIM_SIZE;
            alpha = 0;
        }
        frontRectLeftBegin = frontRectLeft;
    }

    private int measureDimension(int defaultSize, int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = defaultSize; // UNSPECIFIED
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (shape == SHAPE_RECT) {
            paint.setColor(closeColor);
            canvas.drawRect(backRect, paint);
            paint.setColor(openColor);
            paint.setAlpha(alpha);
            canvas.drawRect(backRect, paint);
            frontRect
                    .set(frontRectLeft, RIM_SIZE, frontRectLeft + getMeasuredWidth() / 2 - RIM_SIZE, getMeasuredHeight() - RIM_SIZE);
            paint.setColor(Color.WHITE);
            canvas.drawRect(frontRect, paint);
        } else {
            // draw circle
            int radius;
            radius = backRect.height() / 2;
            paint.setColor(closeColor);
            backCircleRect.set(backRect);
            canvas.drawRoundRect(backCircleRect, radius, radius, paint);
            paint.setColor(openColor);
            paint.setAlpha(alpha);
            canvas.drawRoundRect(backCircleRect, radius, radius, paint);
            frontRect.set(frontRectLeft, RIM_SIZE, frontRectLeft + backRect.height() - 2 * RIM_SIZE, backRect.height() - RIM_SIZE);
            frontCircleRect.set(frontRect);
            paint.setColor(Color.WHITE);
            canvas.drawRoundRect(frontCircleRect, radius, radius, paint);
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (slideable == false)
            return super.onTouchEvent(event);
        int action = MotionEventCompat.getActionMasked(event);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                eventStartX = (int) event.getRawX();
                break;
            case MotionEvent.ACTION_MOVE:
                eventLastX = (int) event.getRawX();
                diffX = eventLastX - eventStartX;
                int tempX = diffX + frontRectLeftBegin;
                tempX = (tempX > maxLeft ? maxLeft : tempX);
                tempX = (tempX < minLeft ? minLeft : tempX);
                if (tempX >= minLeft && tempX <= maxLeft) {
                    frontRectLeft = tempX;
                    alpha = (int) (255 * (float) tempX / (float) maxLeft);
                    invalidateView();
                }
                break;
            case MotionEvent.ACTION_UP:
                int wholeX = (int) (event.getRawX() - eventStartX);
                frontRectLeftBegin = frontRectLeft;
                boolean toRight;
                toRight = (frontRectLeftBegin > maxLeft / 2 ? true : false);
                if (Math.abs(wholeX) < 3) {
                    toRight = !toRight;
                }
                moveToDest(toRight);
                break;
            default:
                break;
        }
        return true;
    }

    /**
     * draw again
     */
    private void invalidateView() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            invalidate();
        } else {
            postInvalidate();
        }
    }

    public void setSlideListener(SlideListener listener) {
        this.mSlideListener = listener;
    }

    public void moveToDest(final boolean toRight) {
        ValueAnimator toDestAnim = ValueAnimator.ofInt(frontRectLeft, toRight ? maxLeft : minLeft);
        toDestAnim.setDuration(300);
        toDestAnim.setInterpolator(new AccelerateDecelerateInterpolator());
        toDestAnim.start();
        toDestAnim.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                frontRectLeft = (Integer) animation.getAnimatedValue();
                alpha = (int) (255 * (float) frontRectLeft / (float) maxLeft);
                invalidateView();
            }
        });
        toDestAnim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (toRight) {
                    isOpen = true;
                    frontRectLeftBegin = maxLeft;
                } else {
                    isOpen = false;
                    frontRectLeftBegin = minLeft;
                }

                if (mSlideListener != null)
                    mSlideListener.onStatusChanged(SlideSwitcher.this, isOpen);
            }
        });
    }

    public void setOpen(boolean isOpen) {
        setOpen(isOpen, false);
    }

    public void setOpen(boolean isOpen, boolean invokListener) {
        this.isOpen = isOpen;
        initDrawingVal();
        invalidateView();
        if (invokListener && mSlideListener != null) mSlideListener.onStatusChanged(this, isOpen);
    }

    public void setShapeType(int shapeType) {
        this.shape = shapeType;
    }

    public void setSlideable(boolean slideable) {
        this.slideable = slideable;
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            this.isOpen = bundle.getBoolean("isOpen");
            state = bundle.getParcelable("instanceState");
        }
        super.onRestoreInstanceState(state);
    }

    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable("instanceState", super.onSaveInstanceState());
        bundle.putBoolean("isOpen", this.isOpen);
        return bundle;
    }
}




下面呢是在布局中使用(注意:**要改成你们自己的包名路径哦!)

//在布局中使用
 <com.***.SlideSwitcher
                android:id="@+id/switch_btn"
                android:layout_width="48dp"
                android:layout_height="28dp"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true" />


到这里就OK了,哈哈,是不是很简单呢!如果对你有那么一丢丢帮助的话,我就很开心啦!
喜欢的话就赞一个哟!谢谢啦!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于 Android 开关按钮的背景图和自定义控件,我可以为您提供一些学习笔记和分享。 1. Android 开关按钮背景图 在 Android 中,开关按钮的背景图可以通过 drawable 文件夹下的 xml 文件来实现。以下是一个简单的例子: ```xml <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/switch_on" android:state_checked="true"/> <item android:drawable="@drawable/switch_off"/> </selector> ``` 其中,我们使用了 selector 标签来表示按钮的状态。在 checked 为 true 时,使用 switch_on 图片作为背景图;否则使用 switch_off 图片作为背景图。 2. Android 自定义控件之开关按钮学习笔记分享 如果您想完全自定义一个开关按钮控件,以下是一些实现步骤: 1) 创建一个继承自 CompoundButton 的,例如 SwitchButton。 2) 实现 SwitchButton 的构造函数和一些必要的属性。 ```java public class SwitchButton extends CompoundButton { public SwitchButton(Context context) { super(context); init(); } public SwitchButton(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SwitchButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 初始化一些属性 } } ``` 3) 在 init() 方法中,设置一些默认属性,例如背景图、文字等。 4) 重写 onMeasure() 方法,计算出 SwitchButton 的宽高。 ```java @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(widthSize, heightSize); } ``` 5) 重写 onDraw() 方法,绘制 SwitchButton 的背景图和文字。 ```java @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制背景图和文字 } ``` 6) 重写 onTouchEvent() 方法,处理用户的触摸事件,例如改变 SwitchButton 的状态。 ```java @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 处理按下事件 break; case MotionEvent.ACTION_MOVE: // 处理移动事件 break; case MotionEvent.ACTION_UP: // 处理抬起事件 break; } return super.onTouchEvent(event); } ``` 7) 最后,将 SwitchButton 添加到布局文件中即可。 ```xml <com.example.myapp.SwitchButton android:id="@+id/switchButton" android:layout_width="wrap_content" android:layout_height="wrap_content"/> ``` 以上就是自定义开关按钮控件的一些步骤和注意事项。希望对您有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值