1. 简介

使用华为手机,发现设置应用中的开关空间颜色听挺好看,所以自己想写一个类似的,当然不可能完全相同,但是大致的效果差不多。 操作步骤:

  1. 截图。PS取色;
  2. 判断左右两边的半径;
  3. 继承View复写onDraw方法,手动绘制。
  4. 控制开关的状态:on/off

    2. 效果

这里写图片描述

3. 实现

3.1 自定义属性

没有定义,颜色和半径都是按照自己的效果写成固定的,当然也可以写成自定义属性。

3.2 自定义View代码

涉及到一些动画的使用和View的事件处理

public class CustomSwitchView extends View {
    /**
     * 开关圆点颜色
     */
    private final int SWITCH_DOT_COLOR = 0xffffffff;

    /**
     * 关闭状态下的背景颜色
     */
    private final int OFF_BACKGROUND_COLOR = 0xffe2e2e2;

    /**
     * 打开状态下的背景颜色
     */
    private final int ON_BACKGROUND_COLOR = 0xff007dff;

    /**
     * 边界和开关圆点的间距
     */
    private final int BOUND_DOT_GAP = 8;

    /**
     * 是否打开
     */
    private boolean isOn = false;

    /**
     * 圆点的半径和坐标位置
     */
    private int mRadius;

    private int startX;
    private int endX;
    private float centerX;
    private float centerY;
    private RectF mRectF;

    /**
     * 开关的画笔
     */
    private Paint mSwitchPaint;

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

    public CustomSwitchView(Context context,
            @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomSwitchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * 打开或者关闭
     *
     * @param on true 打开, false 关闭
     */
    public void setOn(boolean on) {
        isOn = on;
        ValueAnimator animator;
        if (on) {
            animator = ValueAnimator.ofFloat(centerX, endX);
        } else {
            animator = ValueAnimator.ofFloat(centerX, startX);
        }
        animator.setDuration(200);
        animator.setRepeatCount(0);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                centerX = (Float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.start();
    }

    private void init() {
        mSwitchPaint = new Paint();
        mSwitchPaint.setColor(OFF_BACKGROUND_COLOR);
        mSwitchPaint.setStrokeWidth(10f);
        mSwitchPaint.setStrokeCap(Paint.Cap.ROUND);
        mSwitchPaint.setAntiAlias(true);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mRectF = new RectF(getLeft(), getTop(), getRight(), getBottom());
        mRadius = h / 2 - BOUND_DOT_GAP;
        startX = getLeft() + mRadius + BOUND_DOT_GAP / 2;
        endX = getRight() - mRadius - BOUND_DOT_GAP / 2;
        centerX = startX;
        centerY = (getTop() + getBottom()) / 2.0f;
    }

    @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) {
        super.onDraw(canvas);
        if (isOn) {
            mSwitchPaint.setColor(ON_BACKGROUND_COLOR);
        } else {
            mSwitchPaint.setColor(OFF_BACKGROUND_COLOR);
        }
        canvas.drawRoundRect(mRectF, mRadius, mRadius, mSwitchPaint);
        mSwitchPaint.setColor(SWITCH_DOT_COLOR);
        canvas.drawCircle(centerX, centerY, mRadius, mSwitchPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_UP:
                setOn(!isOn);
                break;
            case MotionEvent.ACTION_MOVE: {
                float x = event.getX();
                if (x < endX && x > startX) {
                    centerX = x;
                    invalidate();
                }
            }
            break;
            default:
                break;
        }
        return true;
    }
}

4. 源码

源码依然是上传到Github CustomViewDemo

results matching ""

    No results matching ""