Skip to content

Instantly share code, notes, and snippets.

@gipi
Created October 7, 2011 09:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gipi/1269860 to your computer and use it in GitHub Desktop.
Save gipi/1269860 to your computer and use it in GitHub Desktop.
Customized Segmented button
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SegmentedButton">
<attr name="gradientNormal" format="reference"/>
<attr name="gradientChecked" format="reference"/>
</declare-styleable>
</resources>
/**
* Customization of the RadioButton in order to allow behaviour
* and appearance like the iOS ones.
*
* Inspired from http://blog.bookworm.at/2010/10/segmented-controls-in-android.html
*/
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.GradientDrawable;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.Style;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.GradientDrawable.Orientation;
import android.util.AttributeSet;
import android.widget.RadioButton;
// a day read this
// http://kahdev.wordpress.com/2008/09/13/making-a-custom-android-button-using-a-custom-view/
// copy from LabelView custom view example from sample code
public class SegmentedButton extends RadioButton {
private float mX;
private float mTextWidth;
private float mCurrentWidth;
private float mCurrentHeight;
private int mAscent;
private String mText;
private Paint mTextPaint;
private GradientDrawable mGradient = new GradientDrawable(Orientation.TOP_BOTTOM, new int[] { 0xffdcdcdc, 0xff111111 });;
private GradientDrawable mGradientChecked = new GradientDrawable(Orientation.TOP_BOTTOM, new int[] { 0xffa5a5a5, 0xff000000 });;
public SegmentedButton(Context context) {
super(context);
init(context, null, 0);
}
public SegmentedButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
/**
* This methods inits the style configuration.
*
* For some reason if not called explicitely the checking doesn't work.
*/
protected void init(Context context, AttributeSet attrs, int defStyle) {
// retrieve text for the button
mText = getText().toString();
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(14);
mTextPaint.setColor(0xFF000000);
setPadding(3, 3, 3, 3);
TypedArray a =
context.obtainStyledAttributes(
attrs,
R.styleable.SegmentedButton,
defStyle,
0);
/*
* TODO: text align, padding, margin, text color etc...
*/
final int N = a.getIndexCount();
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.SegmentedButton_gradientNormal:
mGradient = (GradientDrawable)a.getDrawable(attr);
break;
case R.styleable.SegmentedButton_gradientChecked:
mGradientChecked = (GradientDrawable)a.getDrawable(attr);
break;
}
}
}
public SegmentedButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
@Override
public void onDraw(Canvas canvas) {
if (isChecked()) {
GradientDrawable grad = mGradient;
grad.setBounds(0, 0, this.getWidth(), this.getHeight());
grad.draw(canvas);
} else {
GradientDrawable grad = mGradientChecked;
grad.setBounds(0, 0, this.getWidth(), this.getHeight());
grad.draw(canvas);
}
Rect bounds = new Rect();
mTextPaint.getTextBounds(mText, 0, mText.length(), bounds);
canvas.drawText(mText, -bounds.width()/2 + getWidth()/2, getPaddingTop() - mAscent, mTextPaint);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Style.STROKE);
Rect rect = new Rect(0, 0, this.getWidth(), this.getHeight());
canvas.drawRect(rect, paint);
}
/*
@Override
protected void onSizeChanged(int w, int h, int ow, int oh) {
android.util.Log.i("onSizeChanged", "miao");
super.onSizeChanged(w, h, ow, oh);
mX = w * 0.5f; // remember the center of the screen
}*/
@Override
public void onMeasure(int width, int height) {
android.util.Log.i("onMeasure", "width: " + width + " height: " + height);
mAscent = (int)mTextPaint.ascent();
//setMeasuredDimension(getMeasurement(width, bounds.width()), getMeasuredHeight());
setMeasuredDimension(
getMeasurement(width, (int)mTextPaint.measureText(mText)),
getMeasurement(
height,
(int)mTextPaint.descent()-mAscent+getPaddingTop() + getPaddingBottom())
);
//setMeasuredDimension((int)mCurrentWidth, (int)mCurrentHeight);
//super.onMeasure(width, height);
}
private int getMeasurement(int measureSpec, int preferred) {
int specSize = MeasureSpec.getSize(measureSpec);
int measurement = 0;
switch(MeasureSpec.getMode(measureSpec)) {
case MeasureSpec.EXACTLY:
// This means the width of this view has been given.
measurement = specSize;
break;
case MeasureSpec.AT_MOST:
// Take the minimum of the preferred size and what
// we were told to be.
measurement = Math.min(preferred, specSize);
break;
default:
measurement = preferred;
break;
}
return measurement;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment