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;
}
}
<declare-styleable name="SwitchButton">
<attr name="textSize" format="dimension"/>
<attr name="selected_color" format="color"/>
<attr name="stroke_width" format="dimension"/>
declare-styleable>