SwitchButton

实现下图的按钮效果

SwitchButton_第1张图片

  • shape文件实现 是一个RadioGroup,里面是俩个RadioButton,设置不同的点击状态的背景
  • extends View实现

    这里采用第二种实现

public class SwitchButton extends View {
    private float mStrokeWidth = 4.0f;
    private String[] mTabTexts = {"按金额", "按销量"};
    private Paint mStrokePaint;
    private Paint mFillPaint;
    private int mWidth;
    private int mHeight;
    private TextPaint mSelectedTextPaint;
    private TextPaint mUnselectedTextPaint;
    private int mSelectedColor;
    private float mTextSize;
    private Paint.FontMetrics mFontMetrics;
    private float mTextHeightOffset;
    private float mStrokeRadius;
    private int mSelectedTab;
    private SwitchButton.OnSwitchListener onSwitchListener;


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

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

    public SwitchButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initPaint();
    }

    public void setContent(String[] content){
        if (content.length != 2)
            throw new IllegalStateException("String[] length must be 2");
        this.mTabTexts = content;
        invalidate();
    }

    private void initPaint() {
        // round rectangle paint
        mStrokePaint = new Paint();
        mStrokePaint.setColor(mSelectedColor);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setAntiAlias(true);
        mStrokePaint.setStrokeWidth(mStrokeWidth);
        // selected paint
        mFillPaint = new Paint();
        mFillPaint.setColor(mSelectedColor);
        mFillPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mStrokePaint.setAntiAlias(true);
        // selected text paint
        mSelectedTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mSelectedTextPaint.setTextSize(mTextSize);
        mSelectedTextPaint.setColor(0xffffffff);
        mStrokePaint.setAntiAlias(true);
        // unselected text paint
        mUnselectedTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mUnselectedTextPaint.setTextSize(mTextSize);
        mUnselectedTextPaint.setColor(mSelectedColor);
        mStrokePaint.setAntiAlias(true);
        mTextHeightOffset = -(mSelectedTextPaint.ascent() + mSelectedTextPaint.descent()) * 0.5f;
        mFontMetrics = mSelectedTextPaint.getFontMetrics();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.SwitchButton);
        mSelectedColor = array.getColor(R.styleable.SwitchButton_selected_color,0xffeb7b00);
        mTextSize = array.getDimension(R.styleable.SwitchButton_textSize,15f);
        mStrokeWidth = array.getDimension(R.styleable.SwitchButton_stroke_width,mStrokeWidth);
        array.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int defaultWidth = getDefaultWidth();
        int defaultHeight = getDefaultHeight();
        setMeasuredDimension(getExpectSize(defaultWidth, widthMeasureSpec), getExpectSize(defaultHeight,
                heightMeasureSpec));
    }


    private int getDefaultHeight() {
        return (int) (mFontMetrics.bottom - mFontMetrics.top) + getPaddingTop() + getPaddingBottom();
    }
    /**
     * get default width when android:layout_width="wrap_content"
     */
    private int getDefaultWidth() {
        float tabTextWidth = 0f;
        int tabs = mTabTexts.length;
        for (int i = 0; i < tabs; i++) {
            tabTextWidth = Math.max(tabTextWidth, mSelectedTextPaint.measureText(mTabTexts[i]));
        }
        float totalTextWidth = tabTextWidth * tabs;
        float totalStrokeWidth = (mStrokeWidth * tabs);
        int totalPadding = (getPaddingRight() + getPaddingLeft()) * tabs;
        return (int) (totalTextWidth + totalStrokeWidth + totalPadding);
    }

    /**
     * get expect size
     *
     * @param size
     * @param measureSpec
     * @return
     */
    private int getExpectSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        switch (specMode) {
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                result = size;
                break;
            case MeasureSpec.AT_MOST:
                result = Math.min(size, specSize);
                break;
            default:
                break;
        }
        return result;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float left = mStrokeWidth * 0.5f;
        float top = mStrokeWidth * 0.5f;
        float right = mWidth - mStrokeWidth * 0.5f;
        float bottom = mHeight - mStrokeWidth * 0.5f;
        //draw rounded rectangle
        canvas.drawRoundRect(new RectF(left, top, right, bottom), mStrokeRadius, mStrokeRadius, mStrokePaint);
        float centerX = (float) (mWidth * 0.5);
        float centerY = (float) (mHeight * 0.5);
        if (mSelectedTab == 0){
            Path leftPath = new Path();
            leftPath.moveTo(left + mStrokeRadius, top);
            leftPath.lineTo( centerX - 2 * left - mStrokeRadius,top);
            leftPath.arcTo(new RectF(centerX - left - 2 *mStrokeRadius , top, centerX - left, bottom), 270, 180);
            leftPath.lineTo( centerX - left - mStrokeRadius,bottom);
            leftPath.lineTo( left + mStrokeRadius,bottom);
            leftPath.arcTo(new RectF(left , top, left + 2 * mStrokeRadius, bottom), 90, 180);
            canvas.drawPath(leftPath, mFillPaint);

            float tabTextWidth = mSelectedTextPaint.measureText(mTabTexts[mSelectedTab]);
            // draw selected text
            canvas.drawText(mTabTexts[mSelectedTab], (float) ((centerX - tabTextWidth) * 0.5), mHeight * 0.5f +
                    mTextHeightOffset, mSelectedTextPaint);

            float tabTextWidth1 = mSelectedTextPaint.measureText(mTabTexts[mSelectedTab + 1]);
            //draw unselected text
            canvas.drawText(mTabTexts[mSelectedTab  + 1], centerX + (float) ((centerX - tabTextWidth1) * 0.5), mHeight * 0.5f +
                    mTextHeightOffset, mUnselectedTextPaint);

        } else {
            float start = centerX + left;
            Path leftPath = new Path();
            leftPath.moveTo(start + mStrokeRadius, top);
            leftPath.lineTo( mWidth - 2 * left - mStrokeRadius,top);
            leftPath.arcTo(new RectF(mWidth - left - 2 *mStrokeRadius , top, mWidth - left, bottom), 270, 180);
            leftPath.lineTo( mWidth - left - mStrokeRadius,bottom);
            leftPath.lineTo( start + mStrokeRadius,bottom);
            leftPath.arcTo(new RectF(start , top, start + 2 * mStrokeRadius, bottom), 90, 180);
            canvas.drawPath(leftPath, mFillPaint);

            float tabTextWidth = mSelectedTextPaint.measureText(mTabTexts[mSelectedTab]);
            // draw selected text
            canvas.drawText(mTabTexts[mSelectedTab], centerX + (float) ((centerX - tabTextWidth) * 0.5), mHeight * 0.5f +
                    mTextHeightOffset, mSelectedTextPaint);

            float tabTextWidth1 = mSelectedTextPaint.measureText(mTabTexts[mSelectedTab - 1]);
            //draw unselected text
            canvas.drawText(mTabTexts[mSelectedTab  - 1], (float) ((centerX - tabTextWidth1) * 0.5), mHeight * 0.5f +
                    mTextHeightOffset, mUnselectedTextPaint);
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            float x = event.getX();
            int half = mWidth / 2;
            int index = 0;
            if (x < half){
                index = 0;
            } else if (x > half){
                index = 1;
            }
            if (mSelectedTab == index){
                return true;
            } else {
                mSelectedTab = index;
                if (onSwitchListener != null) {
                    onSwitchListener.onSwitch(index, mTabTexts[index]);
                }
                invalidate();
            }

        }
        return true;
    }
    /**
     * called after onMeasure
     *
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
        mStrokeRadius = (float) (mHeight / 2.0 - mStrokeWidth*0.5);
    }

    public interface OnSwitchListener {
        void onSwitch(int position, String tabText);
    }

    public SwitchButton setOnSwitchListener(@NonNull OnSwitchListener onSwitchListener) {
        this.onSwitchListener = onSwitchListener;
        return this;
    }
}

arrrs.xml文件内容是

 <declare-styleable name="SwitchButton">
        <attr name="textSize" format="dimension"/>
        <attr name="selected_color" format="color"/>
        <attr name="stroke_width" format="dimension"/>
    declare-styleable>

你可能感兴趣的:(android)