Android-自定义可滑动开关控件之SlidingSwitchView

首先上两张蹩脚的效果图:

  

效果:可以点击切换,也可以拖动切换


先上代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >

    <com.example.slidingswitchview.slideswitch.SlidingSwitchView
        android:id="@+id/swithview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

1,初始化部分:

    private Bitmap mSwitch_on, mSwitch_off, mTthumb;
    private Paint mPaint;

    private int viewWidth, viewHeigth, thumbWidthHalf, thumbWidth;

    //记录上一次点击的X坐标和当前的X坐标
    private int mLastX, mCurrentX;

    // 是否滑动
    private boolean isScrolling = false;
    // 开关所在的方向,左or右
    private boolean isSwitchLeft = false;
    // 是否是移动状态
    private boolean isMoving = false;
    //是否移动过,如果为false代表是单机时间
    private boolean hasMoving = false;
    
    private int mMoveDistance = 0;
    private int mMoveX = 0;

    private FontMetrics mFontMetrics;
    private float mTextX, mTextY;
    private String mOnText = "on";
    private String mOffText = "off";
    // 0:静止、1:向左、2:向右
    private int mScrollingStatus = 0;

    private static final float GESTURE_THRESHOLD_DIP = 10.0f;
    final float scale = getContext().getResources().getDisplayMetrics().density;

    private IOnSwitchChangerListener mChangerListener = null;

    public SlidingSwitchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initBitmapResource();
        initConstant();
        initPaint();
        initFontMetrics();
    }

    private void initConstant() {
        viewWidth = mSwitch_on.getWidth() + getPaddingLeft() + getPaddingRight();
        viewHeigth = mSwitch_on.getHeight() + getPaddingTop() + getPaddingBottom();
        thumbWidth = mTthumb.getWidth();
        thumbWidthHalf = thumbWidth / 2;
        if (isSwitchLeft) {
            mMoveDistance = 0;
        } else {
            mMoveDistance = viewWidth - thumbWidthHalf;
        }
        mScrollingStatus = 0;
    }

    private void initBitmapResource() {
        mSwitch_on = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.on);
        mSwitch_off = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.off);
        mTthumb = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.thumb);
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    private void initFontMetrics() {
        // viewWidth: 155,
        // viewHeigth: 61
        // ascent: -11.1328125
        // top: -12.673828
        // bottom: 3.2519531 ,
        // descent: 2.9296875 ,
        // leading: 0.0 ,
        mPaint.setTextSize(getTextSize(GESTURE_THRESHOLD_DIP));
        mFontMetrics = mPaint.getFontMetrics();
        mTextX = (viewWidth >> 1) - (int) (mPaint.measureText(mOnText)) >> 1;
        // baseline位置字体下基准线位置
        // mTextY代表baseline的位置 字体高度为:(mFontMetrics.descent -
        // mFontMetrics.ascent) / 2
        // 字体上下居中的推到公式为:控件高度/2 + 字体高度/2 -
        // mFontMetrics.bottom(注:bottom的高度通常情况下比较小)
        mTextY = ((mFontMetrics.descent - mFontMetrics.ascent) / 2 - mFontMetrics.bottom) + viewHeigth / 2;
    }

注:initFontMetrics()方法是在是因为没有现成的图,就手动把文字写上去尴尬


2,绘制部分:


重写onDraw方法完成绘制,分3种情况:1、手指移动状态:isMoveing 2、控件处于滑动状态:isScrolling 3、初始化状态  。  其中isScrolling状态分为手指滑动过和未滑动过(也视为单击状态)两种情况。通过mMoveDistance和mCurrentX判断如何绘制

重写onTouchEvent方法,ACTION_UP中hasMoving判断此次点击是不是单击事件。

    @Override
    protected void onDraw(Canvas canvas) {
        if (isMoving) {
            if (mMoveDistance <= 0) {
                drawbitmap(canvas, 0, 0);
            } else if (mMoveDistance >= viewWidth - thumbWidth) {
                drawbitmap(canvas, viewWidth - thumbWidthHalf, viewWidth - thumbWidth);
            } else {
                drawbitmap(canvas, mMoveDistance + thumbWidthHalf, mMoveDistance);
            }
        } else if (isScrolling) {
            drawbitmap(canvas, mMoveDistance + thumbWidthHalf, mMoveDistance);
            // 点击向右滑动
            if (mCurrentX > viewWidth / 2 && mScrollingStatus == 2) {
                mMoveDistance = mMoveDistance + SCROLLING_OFFSET;
            }
            // 点击向左滑动
            else if (mCurrentX <= viewWidth / 2 && mScrollingStatus == 1) {
                mMoveDistance = mMoveDistance - SCROLLING_OFFSET;
            } else
            // MOVE向右滑动
            if (mMoveDistance + thumbWidthHalf > viewWidth / 2) {
                mMoveDistance = mMoveDistance + SCROLLING_OFFSET;
            }
            // MOVE向左滑动
            else {
                mMoveDistance = mMoveDistance - SCROLLING_OFFSET;
            }
            refreshState();
        } else {
            // 初始化状态 这个应该跟外部关联
            drawbitmap(canvas, mMoveDistance, mMoveDistance == 0 ? 0 : viewWidth - thumbWidth);
            mLastX = 0;
            mCurrentX = 0;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isScrolling) {
            return true;
        }
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mLastX = (int) event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            isMoving = true;
            hasMoving = true;
            mCurrentX = (int) event.getX();
            mMoveX = mCurrentX - mLastX;
            mLastX = mCurrentX;
            mMoveDistance = mMoveDistance + mMoveX;
            postInvalidate();
            break;
        case MotionEvent.ACTION_UP:
            isMoving = false;
            mCurrentX = (int) event.getX();
            if (!hasMoving) {
                if (mCurrentX < viewWidth / 2 && !isSwitchLeft) {
                    mMoveDistance = viewWidth - thumbWidth - SCROLLING_OFFSET;
                    mScrollingStatus = 1;
                } else if (mCurrentX >= viewWidth / 2 && isSwitchLeft) {
                    mMoveDistance = mMoveDistance + SCROLLING_OFFSET;
                    mScrollingStatus = 2;
                }
                hasMoving = false;
            }

            refreshState();
            break;
        default:
            break;
        }
        return true;
    }

    private void refreshState() {
        if (mScrollingStatus != 0 && (viewWidth - thumbWidth > mMoveDistance && mMoveDistance > 0)) {
            isScrolling = true;
        } else {
            if (mMoveDistance <= 0) {
                relaseConstant();
                mMoveDistance = 0;
                isSwitchLeft = true;
                if (mChangerListener != null) {
                    mChangerListener.onSwitchChanger(this, isSwitchLeft);
                }
            } else if (mMoveDistance >= viewWidth - thumbWidth) {
                relaseConstant();
                mMoveDistance = viewWidth - thumbWidthHalf;
                isSwitchLeft = false;
                if (mChangerListener != null) {
                    mChangerListener.onSwitchChanger(this, isSwitchLeft);
                }
            } else {
                isScrolling = true;
            }
        }
        postInvalidate();
    }

    private void relaseConstant() {
        isMoving = false;
        isScrolling = false;
        hasMoving = false;
        mScrollingStatus = 0;
    }

    /**
     * 绘制按钮
     * 
     * @param canvas
     * @param mDistance
     * @param mTthumb_to_left
     */
    private void drawbitmap(Canvas canvas, int mDistance, int mTthumb_to_left) {
        canvas.drawBitmap(mSwitch_on, new Rect(0, 0, mDistance, viewHeigth), new Rect(0, 0, mDistance, viewHeigth), mPaint);
        mPaint.setColor(Color.WHITE);
        canvas.drawText(mOnText, getTextSize(GESTURE_THRESHOLD_DIP), mTextY, mPaint);
        canvas.drawBitmap(mSwitch_off, new Rect(mDistance, 0, viewWidth, viewHeigth), new Rect(mDistance, 0, viewWidth, viewHeigth), mPaint);
        mPaint.setColor(Color.GRAY);
        canvas.drawText(mOffText, viewWidth / 2 + getTextSize(12f), mTextY, mPaint);
        canvas.drawBitmap(mTthumb, mTthumb_to_left, 0, mPaint);
    }

demo戳这里:点击打开链接
写博客,更多的是对自己的一个积累,方便日后总结。最后贴出代码,代码不是很好,欢迎指正!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值