不得不说,在做自定义滑动开关过程中,学习到了很多东西。跟大家分享分享!

1、自定义控件步骤:

测量:onMeasure  设置自己显示在屏幕上的宽高


布局:onLayout   设置自己显示在屏幕上的位置(只有在自定义ViewGroup中才用到,需要设置子view的位置)

绘制:onDraw     控制显示在屏幕上的样子(自定义viewgroup时不需要这个,绘制单个view的样子)


所以我们在自定义一个控件之前,要明白自定义的是一个view,还是一个viewgroup,如:本篇中自定义的ToggleButton

只是一个简单view,本人是这样理解的:view相当于button,textview之类的小控件,而viewgroup相当于RelativeLayout

之类的布局。大家可以提出个人的见解让他人可以更好的理解view与viewgroup的差别!

View和ViewGroup的区别
1.他们都需要进行测量操作
2.ViewGroup主要是控制子view如何摆放,所以必须实现onLayout
  View没有子view,所以不需要onLayout方法,但是必须实现onDraw

3、废话有点多,先贴出ToggleButton效果图:

android 拖动 选择 android 滑动按钮_自定义控件步骤

android 拖动 选择 android 滑动按钮_android 拖动 选择_02

4、源码:xml中很简单:

<com.chenshi.mytogglebutton.ToggleButton
    android:id="@+id/toggleBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true" />


最后一句是使view居于父控件居中!


5、MainActivity中:


toggleButton.setSildeBackgroundResource(R.drawable.slide_bg);
toggleButton.setSwitchOnBackgroundResource(R.drawable.switch_on);
toggleButton.setSwitchOffBackgroundResource(R.drawable.switch_off);
//设置开关状态,默认为OPEN
toggleButton.setToggleState(ToggleButton.ToggleState.CLOSE);
toggleButton.setOnStateChangeListeren(new ToggleButton.OnToggleStateChangeListeren() {
    @Override
    public void onToggleStateChangeListeren(ToggleButton.ToggleState toggleState) {
        Toast.makeText(MainActivity.this, toggleState == ToggleButton.ToggleState.CLOSE ? "关" : "开",
Toast.LENGTH_SHORT).show();
    }
});
为什么要先贴出MainActivity中源码呢,因为我们通过set知道我们自定中需要哪里方法,如:
toggleButton.setSildeBackgroundResource(R.drawable.slide_bg);对应于自定类ToggleButton中就要有
/**
 * 设置滑块的背景图片
 *
 * @param slide_bg
 */
public void setSildeBackgroundResource(int slide_bg) {
    slideBg = BitmapFactory.decodeResource(getResources(), slide_bg);
}

此方法!这是一种思路!并不是盲目的自定义方法!

6、自定类源码:注释的挺详细的,大家耐心点看!



public class ToggleButton extends View {
    private Bitmap slideBg;//滑块的背景图
    private Bitmap switchOn;//滑动开关开的背景图
    private Bitmap switchOff;//滑动开关关的背景图

    private ToggleState state = ToggleState.OPEN;//滑动开关的状态,默认为OPEN;
    //手指触摸在view上的坐标,这个是相对于view的坐标
    private int currentX;
    //是否在滑动
    private boolean isSliding = true;

    /**
     * 如果自定的控件需要在Java中实例化,重写该构造方法
     *
     * @param context
     */
    public ToggleButton(Context context) {
        super(context);
    }

    /**
     * 如果自定义控件需要在xml文件使用,重写该构造方法
     *
     * @param context
     * @param attrs
     */
    public ToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 设置滑块的背景图片
     *
     * @param slide_bg
     */
    public void setSildeBackgroundResource(int slide_bg) {
        slideBg = BitmapFactory.decodeResource(getResources(), slide_bg);
    }

    /**
     * 设置滑动开关开的背景图
     *
     * @param switch_on
     */
    public void setSwitchOnBackgroundResource(int switch_on) {
        switchOn = BitmapFactory.decodeResource(getResources(), switch_on);
    }

    /**
     * 设置滑动开关关的背景图
     *
     * @param switch_off
     */
    public void setSwitchOffBackgroundResource(int switch_off) {
        switchOff = BitmapFactory.decodeResource(getResources(), switch_off);
    }

    public void setToggleState(ToggleState toggleState) {
        this.state = toggleState;
    }

    public enum ToggleState {
        OPEN, CLOSE
    }

    /**
     * 绘制view的宽与高,以滑动开关的宽高绘制
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(switchOn.getWidth(), switchOn.getHeight());
    }

    /**
     * 画view
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        int left = currentX - slideBg.getWidth() / 2;
        // (left > (switchOn.getWidth() / 2)) ? ((state = ToggleState.OPEN)) : ((state = ToggleState.CLOSE));
        //当触摸点超过整view的一半时,就切换开关背景;

        super.onDraw(canvas);
        /**
         * (@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint)
         * left:图片左边的x坐标
         * top:图片顶部的y坐标
         */
        if (isSliding) {
            if (state == ToggleState.OPEN) {
                //绘制开关图片
                canvas.drawBitmap(switchOn, 0, 0, null);
                //绘制滑块图片
                if (left > (switchOn.getWidth() - slideBg.getWidth()))
                    left = switchOn.getWidth() - slideBg.getWidth();
                canvas.drawBitmap(slideBg, left, 0, null);
            } else {
                //绘制开关图片
                canvas.drawBitmap(switchOff, 0, 0, null);
                //绘制滑块图片
                if (left < 0) left = 0;
                canvas.drawBitmap(slideBg, left, 0, null);
            }
        } else {
            if (state == ToggleState.OPEN) {
                //绘制开关图片
                canvas.drawBitmap(switchOn, 0, 0, null);

                canvas.drawBitmap(slideBg, switchOn.getWidth() - slideBg.getWidth(), 0, null);
            } else {
                //绘制开关图片
                canvas.drawBitmap(switchOff, 0, 0, null);

                canvas.drawBitmap(slideBg, 0, 0, null);
            }
        }

    }

    /**
     * 定义滑动
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        currentX = (int) event.getX();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isSliding = true;
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                isSliding = false;
                break;
        }
       //在滑动的过程中状态改变也进行监听,触摸结束后也监听状态改变,未改变就无需其他动作
         if (currentX > switchOn.getWidth() / 2) {
             if (state != ToggleState.OPEN) {
                 state = ToggleState.OPEN;
                 if (stateChangeListeren != null) {
                     stateChangeListeren.onToggleStateChangeListeren(state);
                 }
             }
        } else {
             //CLOSE
             if (state != ToggleState.CLOSE) {
                 state = ToggleState.CLOSE;
                 if (stateChangeListeren != null) {
                     stateChangeListeren.onToggleStateChangeListeren(state);
                 }
             }
        }
        //调用此方法,间接调用OnD
        invalidate();
        return true;
    }

    /**
     * 开放状态改变接口
     */
    private OnToggleStateChangeListeren stateChangeListeren;

    public void setOnStateChangeListeren(OnToggleStateChangeListeren stateChangeListeren) {
        this.stateChangeListeren = stateChangeListeren;
    }

    public interface OnToggleStateChangeListeren {
        void onToggleStateChangeListeren(ToggleState state);
    }
}


免费下载链接: Android自定义滑动开关demo下载链接