How to design charts using canvas in Android? - android

i want to design following charts in android using canvas or other methods please help me...
As Show in image i want to draw sections of circle as per input in percentage Ex. 50% part of circle is red color and 50% part in cream color with some text as show in image.

could be helpful,
public class View_PieChart extends View {
private static final int WAIT = 0;
private static final int IS_READY_TO_DRAW = 1;
private static final int IS_DRAW = 2;
private static final float START_INC = 30;
private Paint mBgPaints = new Paint();
private Paint mLinePaints = new Paint();
private int mOverlayId;
private int mWidth;
private int mHeight;
private int mGapLeft;
private int mGapRight;
private int mGapTop;
private int mGapBottom;
private int mBgColor;
private int mState = WAIT;
private float mStart;
private float mSweep;
private int mMaxConnection;
private List<PieDetailsItem> mDataArray;
//--------------------------------------------------------------------------------------
public View_PieChart (Context context){
super(context);
}
//--------------------------------------------------------------------------------------
public View_PieChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
//--------------------------------------------------------------------------------------
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//------------------------------------------------------
if (mState != IS_READY_TO_DRAW) return;
canvas.drawColor(mBgColor);
//------------------------------------------------------
mBgPaints.setAntiAlias(true);
mBgPaints.setStyle(Paint.Style.FILL);
mBgPaints.setColor(0x88FF0000);
mBgPaints.setStrokeWidth(0.5f);
//------------------------------------------------------
mLinePaints.setAntiAlias(true);
mLinePaints.setStyle(Paint.Style.STROKE);
mLinePaints.setColor(0xff000000);
mLinePaints.setStrokeWidth(0.5f);
//------------------------------------------------------
RectF mOvals = new RectF( mGapLeft, mGapTop, mWidth - mGapRight, mHeight - mGapBottom);
//------------------------------------------------------
mStart = START_INC;
PieDetailsItem Item;
for (int i = 0; i < mDataArray.size(); i++) {
Item = (PieDetailsItem) mDataArray.get(i);
mBgPaints.setColor(Item.Color);
mSweep = (float) 360 * ( (float)Item.Count / (float)mMaxConnection );
canvas.drawArc(mOvals, mStart, mSweep, true, mBgPaints);
canvas.drawArc(mOvals, mStart, mSweep, true, mLinePaints);
mStart += mSweep;
}
//------------------------------------------------------
Options options = new BitmapFactory.Options();
options.inScaled = false;
/*Bitmap OverlayBitmap = BitmapFactory.decodeResource(getResources(), mOverlayId, options);
canvas.drawBitmap(OverlayBitmap, 0.0f, 0.0f, null);*/
//------------------------------------------------------
mState = IS_DRAW;
}
//--------------------------------------------------------------------------------------
public void setGeometry(int width, int height, int GapLeft, int GapRight, int GapTop, int GapBottom, int OverlayId) {
mWidth = width;
mHeight = height;
mGapLeft = GapLeft;
mGapRight = GapRight;
mGapTop = GapTop;
mGapBottom = GapBottom;
mOverlayId = OverlayId;
}
//--------------------------------------------------------------------------------------
public void setSkinParams(int bgColor) {
mBgColor = bgColor;
}
//--------------------------------------------------------------------------------------
public void setData(List<PieDetailsItem> data, int MaxConnection) {
mDataArray = data;
mMaxConnection = MaxConnection;
mState = IS_READY_TO_DRAW;
}
//--------------------------------------------------------------------------------------
public void setState(int State) {
mState = State;
}
//--------------------------------------------------------------------------------------
public int getColorValue( int Index ) {
if (mDataArray == null) return 0;
if (Index < 0){
return ((PieDetailsItem)mDataArray.get(0)).Color;
} else if (Index >= mDataArray.size()){
return ((PieDetailsItem)mDataArray.get(mDataArray.size()-1)).Color;
} else {
return ((PieDetailsItem)mDataArray.get(mDataArray.size()-1)).Color;
}
}
}

you can you chart engine for this type of chart.
check this url:
http://www.artfulbits.com/articles/samples/aicharts/sample-viewer.aspx?sample=piesample
Regards,
Girish

Related

how to click listener on custom view

In one of my apps I have created a circular view with multiple colors,In which I want to set click listener on each color arch
Below is the image and code for drawing that view
Custom view class code
public class CircularStatusView extends View {
private static final float DEFAULT_PORTION_WIDTH = 10;
private static final int DEFAULT_PORTION_SPACING = 5;
private static final int DEFAULT_COLOR = Color.parseColor("#D81B60");
private static final float DEFAULT_PORTIONS_COUNT = 1;
private static final float START_DEGREE =-90;
private float radius;
private float portionWidth = DEFAULT_PORTION_WIDTH;
private int portionSpacing = DEFAULT_PORTION_SPACING;
private int portionColor = DEFAULT_COLOR;
private float portionsCount = DEFAULT_PORTIONS_COUNT;
private RectF mBorderRect = new RectF();
private Paint paint;
private SparseIntArray portionToUpdateMap = new SparseIntArray();
private Context context;
public CircularStatusView(Context context) {
super(context);
init(context, null, -1);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularStatusView, defStyle, 0);
if (a != null) {
portionColor = a.getColor(R.styleable.CircularStatusView_portion_color, DEFAULT_COLOR);
portionWidth = a.getDimensionPixelSize(R.styleable.CircularStatusView_portion_width, (int) DEFAULT_PORTION_WIDTH);
portionSpacing = a.getDimensionPixelSize(R.styleable.CircularStatusView_portion_spacing, DEFAULT_PORTION_SPACING);
portionsCount = a.getInteger(R.styleable.CircularStatusView_portions_count, (int) DEFAULT_PORTIONS_COUNT);
a.recycle();
}
paint = getPaint();
}
public CircularStatusView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs, -1);
}
public CircularStatusView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBorderRect.set(calculateBounds());
radius = Math.min((mBorderRect.height() - portionWidth) / 2.0f, (mBorderRect.width() - portionWidth) / 2.0f);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float radius = this.radius;
float center_x = mBorderRect.centerX();
float center_y = mBorderRect.centerY();
final RectF oval = getOval(radius, center_x, center_y);
float degree = 360 / portionsCount;
float percent = 100 / portionsCount;
for (int i = 0; i < portionsCount; i++) {
paint.setColor(getPaintColorForIndex(i));
float startAngle = START_DEGREE + (degree * i);
canvas.drawArc(oval, (getSpacing() / 2) + startAngle, getProgressAngle(percent) - getSpacing(), false, paint);
}
}
private int getPaintColorForIndex(int i) {
if (portionToUpdateMap.indexOfKey(i) >= 0) { //if key is exists
return portionToUpdateMap.get(i);
} else {
return portionColor;
}
}
#NonNull
private RectF getOval(float radius, float center_x, float center_y) {
final RectF oval = new RectF();
oval.set(center_x - radius,
center_y - radius,
center_x + radius,
center_y + radius);
return oval;
}
#NonNull
private Paint getPaint() {
Paint paint = new Paint();
paint.setColor(portionColor);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeWidth(portionWidth);
paint.setStrokeCap(Paint.Cap.BUTT);
return paint;
}
private int getSpacing() {
return portionsCount == 1 ? 0 : portionSpacing;
}
private RectF calculateBounds() {
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
int sideLength = Math.min(availableWidth, availableHeight);
float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
float top = getPaddingTop() + (availableHeight - sideLength) / 2f;
return new RectF(left, top, left + sideLength, top + sideLength);
}
private float getProgressAngle(float percent) {
return percent / (float) 100 * 360;
}
public void setPortionsCount(int portionsCount) {
this.portionsCount = (float) portionsCount;
}
public void setPortionSpacing(int spacing) {
portionSpacing = spacing;
}
public void setPortionWidth(float portionWidth) {
this.portionWidth = portionWidth;
}
public void setCustomPaint(Paint paint) {
this.paint = paint;
}
public void setPortionsColor(int color) {
this.portionColor = color;
portionToUpdateMap.clear();
invalidate();
}
public void setPortionColorForIndex(int index, int color) {
if (index > portionsCount - 1) {
throw new IllegalArgumentException("Index is Bigger than the count!");
} else {
Log.d("3llomi", "adding index to map " + index);
portionToUpdateMap.put(index, color);
invalidate();
}
}
}
and in my activity class
CircularStatusView circularStatusView = findViewById(R.id.circular_status_view);
circularStatusView.setPortionsCount(6);
for (int i=0; i<AppConstants.outerCircleColors.length; i++){
circularStatusView.setPortionColorForIndex(i,Color.parseColor(AppConstants.outerCircleColors[i]));
How I can set click listener on each color arch in this view? Can someone help me out in this?
You can get the pixel from the CircularStatusView, By using OnTouchListener:
CircularStatusView view = ((CircularStatusView)v);
Bitmap bitmap = ((BitmapDrawable)view.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);
You can just compare the pixel to a different color. Like...
if(pixel == Color.RED){
//It's Red Color
}
You can create an interface listener for onTouch events. Check the onTouch co-ordinates. Depending on their position you can send back the touched part index to the interface listener.
Dummy code:
public class CircularStatusView extends View {
private StatusViewTouchListener listener;
...
..
.
public void setOnClickListener(StatusViewTouchListener listener) {
this.listener = listener;
}
public interface StatusViewTouchListener {
public void onStatusViewTouch(int index);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
int indexOfTouchedColor;
// Check the touch points and determine in which color part it exists.
listener.onStatusViewTouch(indexOfTouchedColor);
return true;
}
}
Implement the listener where where you are using the view and set it to the View.
public class yourActivity extends Activity implements StatusViewTouchListener {
...
..
.
CircularStatusView circularStatusView = findViewById(R.id.circular_status_view);
circularStatusView.setPortionsCount(6);
for (int i=0; i<AppConstants.outerCircleColors.length; i++){
circularStatusView.setPortionColorForIndex(i,Color.parseColor(AppConstants.outerCircleColors[i]));
circularStatusView.setOnClickListener(this);
...
..
#Override
public void onStatusViewTouch(int index) {
// Perform your action based on the index of the color
}
}

set switch button state according to share preference value android

I have a custom switch button which i am using for attendance purpose.I am saving the value in shared prefernces.the values are being retrieved very well but the state of the switch button needs to be changed on create according to value of shared preferences.For example if the value is true then button will be in unchecked state and if false button will be in checked state.how to achieve this?
getPreference();
if(Common.punchedIn) {
// switchButton.setOnCheckedChangeListener(null);
switchButton.setChecked(false);
}
else
{
// switchButton.setOnCheckedChangeListener(null);
switchButton.setChecked(true);
}
switchButton.setOnCheckedChangeListener(new MySwitchButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(MySwitchButton s, boolean isChecked) {
if(switchButton.isChecked()){
String acTime = getActionTime();
String acDate = getActionDate();
String loc = getGPSLocation();
String empID = getEmployeeID();
String empReportingTo = getReportingTo();
//Toast.makeText(AttendanceActivity.this, "Switch is currently ON", Toast.LENGTH_LONG).show();
punchStatus_text.setText("Punch Out");
shift_dur_text.setVisibility(View.INVISIBLE);
shift_dur_time.setVisibility(View.INVISIBLE);
checkin_time.setVisibility(View.VISIBLE);
checkin_time.setText("Check in :"+acTime);
checkout_time.setVisibility(View.INVISIBLE);
saveAttendance(empID,empReportingTo,acDate,acTime,loc,"na","na","IN");
}else{
String acTime = getActionTime();
String acDate = getActionDate();
String loc = getGPSLocation();
String empID = getEmployeeID();
String empReportingTo = getReportingTo();
//Toast.makeText(AttendanceActivity.this, "Switch is currently OFF", Toast.LENGTH_LONG).show();
punchStatus_text.setText("Punch In");
shift_dur_text.setVisibility(View.VISIBLE);
shift_dur_time.setVisibility(View.VISIBLE);
checkin_time.setText("Check in :"+Common.punchInTime);
checkin_time.setVisibility(View.INVISIBLE);
checkout_time.setVisibility(View.VISIBLE);
checkout_time.setText("Check Out:"+acTime);
saveAttendance(empID,empReportingTo,acDate,acTime,loc,"na","na","OUT");
}
}
});
saving and retrieving from share preference
public static boolean setPreference(Context context,boolean value) {
SharedPreferences settings = context.getSharedPreferences("sharedPref", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("punch",value);
return editor.commit();
}
public void getPreference() {
SharedPreferences settings = this.getSharedPreferences("sharedPref", Context.MODE_PRIVATE);
// Toast.makeText(this,"EMP ID is "+emp_id,Toast.LENGTH_LONG).show();
Common.punchedIn = settings.getBoolean("punch", false);
Toast.makeText(this,"PUNCH IN STATUS "+String.valueOf(Common.punchedIn),Toast.LENGTH_LONG).show();
}
SWITCH BUTTON CLASS
public class MySwitchButton extends View implements Checkable {
private static final int ANIMATION_DURATION = 300;
private static final int DEFAULT_WIDTH = 100;
private static final int DEFAULT_HEIGHT = 50;
private static final int DEFAULT_SPOT_PADDING = 6;
private static final int DEFAULT_BORDER_WIDTH = 4;
private static final int DEFAULT_SWITCH_ON_COLOR = Color.LTGRAY;
private static final int DEFAULT_SWITCH_ON_COLOR_OUT = Color.LTGRAY;
private static final int DEFAULT_SWITCH_OFF_COLOR = Color.LTGRAY;
private static final int DEFAULT_SWITCH_OFF_COLOR_OUT = Color.LTGRAY;
private static final int DEFAULT_SPOT_ON_COLOR = R.color.colorBrown;
private static final int DEFAULT_SPOT_ON_COLOR_IN = R.color.colorBrown;
private static final int DEFAULT_SPOT_OFF_COLOR = R.color.colorBrown;
private static final int DEFAULT_SPOT_OFF_COLOR_IN = R.color.colorBrown;
private static final int SWITCH_OFF_POS = 0;
private static final int SWITCH_ON_POS = 1;
private int switchOnColor;
private int switchOffColor;
private int spotOnColor;
private int spotOnColorIn;
private int spotOffColor;
private int spotOffColorIn;
private int switchOnStrokeColor;
private int switchOffStrokeColor;
private int spotPadding;
private float currentPos;
private boolean mChecked;
private boolean mBroadcasting;
private boolean isMoving;
private int duration;
private OnCheckedChangeListener onCheckedChangeListener;
private ValueAnimator valueAnimator;
private enum State {
SWITCH_ANIMATION_OFF, SWITCH_ANIMATION_ON, SWITCH_ON, SWITCH_OFF
}
private State state;
public MySwitchButton(Context context) {
super(context);
switchOnColor = DEFAULT_SWITCH_ON_COLOR;
switchOffColor = DEFAULT_SWITCH_OFF_COLOR;
spotOnColor = DEFAULT_SPOT_ON_COLOR;
spotOnColorIn = DEFAULT_SPOT_ON_COLOR_IN;
spotOffColor = DEFAULT_SPOT_OFF_COLOR;
spotOffColorIn = DEFAULT_SPOT_OFF_COLOR_IN;
spotPadding = dp2px(DEFAULT_SPOT_PADDING);
switchOnStrokeColor = switchOnColor;
switchOffStrokeColor = switchOffColor;
duration = ANIMATION_DURATION;
state = mChecked ? State.SWITCH_ON : State.SWITCH_OFF;
setClickable(true);
}
public MySwitchButton(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Switch);
switchOnColor = a.getColor(R.styleable.Switch_switchOnColor, DEFAULT_SWITCH_ON_COLOR);
switchOffColor = a.getColor(R.styleable.Switch_switchOffColor, DEFAULT_SWITCH_OFF_COLOR);
// switchOnColor = getResources().getColor(R.color.colorBrown);
//switchOffColor = getResources().getColor(R.color.colorBrown);
spotOnColor = a.getColor(R.styleable.Switch_spotOnColor, DEFAULT_SPOT_ON_COLOR);
spotOnColorIn = a.getColor(R.styleable.Switch_spotOnColor, DEFAULT_SPOT_ON_COLOR_IN);
spotOffColor = a.getColor(R.styleable.Switch_spotOffColor, DEFAULT_SPOT_OFF_COLOR);
spotOffColorIn = a.getColor(R.styleable.Switch_spotOnColor, DEFAULT_SPOT_OFF_COLOR_IN);
spotPadding = a.getDimensionPixelSize(R.styleable.Switch_spotPadding, dp2px(DEFAULT_SPOT_PADDING));
switchOnStrokeColor = a.getColor(R.styleable.Switch_switchOnStrokeColor, switchOnColor);
switchOffStrokeColor = a.getColor(R.styleable.Switch_switchOffStrokeColor, switchOffColor);
duration = a.getInteger(R.styleable.Switch_duration, ANIMATION_DURATION);
mChecked = a.getBoolean(R.styleable.Switch_checked, false);
a.recycle();
state = mChecked ? State.SWITCH_ON : State.SWITCH_OFF;
setClickable(true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int width = dp2px(DEFAULT_WIDTH) + getPaddingLeft() + getPaddingRight();
int height = dp2px(DEFAULT_HEIGHT) + getPaddingTop() + getPaddingBottom();
if (widthSpecMode != MeasureSpec.AT_MOST) {
width = Math.max(width, widthSpecSize);
}
if (heightSpecMode != MeasureSpec.AT_MOST) {
height = Math.max(height, heightSpecSize);
}
setMeasuredDimension(width, height);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = getWidth();
int h = getHeight();
int pl = getPaddingLeft();
int pt = getPaddingTop();
int pr = getPaddingRight();
int pb = getPaddingBottom();
int wp = w - pl - pr;
int hp = h - pt - pb;
int sw = dp2px(DEFAULT_WIDTH);
int sh = dp2px(DEFAULT_HEIGHT);
int dx = pl + (wp - sw) / 2;
int dy = pt + (hp - sh) / 2;
canvas.translate(dx, dy);
switch (state) {
case SWITCH_ON:
drawSwitchOn(canvas);
break;
case SWITCH_OFF:
drawSwitchOff(canvas);
break;
case SWITCH_ANIMATION_ON:
drawSwitchOnAnim(canvas);
break;
case SWITCH_ANIMATION_OFF:
drawSwitchOffAnim(canvas);
break;
}
}
private void drawSwitchOn(Canvas canvas) {
float[] rectAttrs = compRoundRectAttr(SWITCH_OFF_POS);
drawRoundRect(canvas, switchOnColor, rectAttrs);
float[] ovalAttrs = compOvalAttr(SWITCH_ON_POS);
drawOval(canvas, spotOnColor, ovalAttrs);
drawOvalIn(canvas, spotOnColorIn, ovalAttrs);
drawRoundRectStroke(canvas, DEFAULT_SWITCH_ON_COLOR_OUT);
}
private void drawSwitchOff(Canvas canvas) {
float[] rectAttrs = compRoundRectAttr(SWITCH_OFF_POS);
drawRoundRect(canvas, switchOffColor, rectAttrs);
float[] ovalAttrs = compOvalAttr(SWITCH_OFF_POS);
drawOval(canvas, spotOffColor, ovalAttrs);
drawOvalIn(canvas, spotOffColorIn, ovalAttrs);
drawRoundRectStroke(canvas, DEFAULT_SWITCH_OFF_COLOR_OUT);
}
private void drawSwitchOnAnim(Canvas canvas) {
float[] rectAttrs = compRoundRectAttr(SWITCH_OFF_POS);
drawRoundRect(canvas, switchOnColor, rectAttrs);
rectAttrs = compRoundRectAttr(currentPos);
drawRoundRect(canvas, switchOffColor, rectAttrs);
float[] ovalShadeOnAttrs = compRoundRectShadeOnAttr(currentPos * 3/2);
float[] ovalAttrs = compOvalAttr(currentPos* 3/2);
int color = compColor(currentPos, DEFAULT_SPOT_OFF_COLOR, DEFAULT_SPOT_ON_COLOR);
int colorIn = compColor(currentPos, DEFAULT_SPOT_OFF_COLOR_IN, DEFAULT_SPOT_ON_COLOR_IN);
drawRoundRect(canvas, color, ovalShadeOnAttrs);
drawOval(canvas, color, ovalAttrs);
drawOvalIn(canvas, colorIn, ovalAttrs);
int strokeColor = compColor(currentPos, DEFAULT_SWITCH_OFF_COLOR_OUT, DEFAULT_SWITCH_ON_COLOR_OUT);
drawRoundRectStroke(canvas, strokeColor);
}
private void drawSwitchOffAnim(Canvas canvas) {
float[] rectAttrs = compRoundRectAttr(SWITCH_OFF_POS);
if (currentPos != 1) {
drawRoundRect(canvas, switchOffColor, rectAttrs);
}
rectAttrs = compRoundRectAttr(1 - currentPos);
drawRoundRect(canvas, switchOffColor, rectAttrs);
float[] ovalAttrs;
if(currentPos > 2.0/3){
ovalAttrs = compOvalAttr(0);
}else{
ovalAttrs = compOvalAttr(1 - currentPos * 3/2);
}
float[] ovalShadeOffAttrs = compRoundRectShadeOffAttr(1 - currentPos * 3/2);
int color = compColor(currentPos, DEFAULT_SPOT_ON_COLOR, DEFAULT_SPOT_OFF_COLOR);
int colorIn = compColor(currentPos, DEFAULT_SPOT_ON_COLOR_IN, DEFAULT_SPOT_OFF_COLOR_IN);
drawRoundRect(canvas, color, ovalShadeOffAttrs);
drawOval(canvas, color, ovalAttrs);
drawOvalIn(canvas, colorIn, ovalAttrs);
int strokeColor = compColor(currentPos, DEFAULT_SWITCH_ON_COLOR_OUT, DEFAULT_SWITCH_OFF_COLOR_OUT);
drawRoundRectStroke(canvas, strokeColor);
}
private void drawRoundRect(Canvas canvas, int color, float[] attrs) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeCap(Paint.Cap.ROUND);
RectF rectF = new RectF();
paint.setColor(color);
rectF.set(attrs[0], attrs[1], attrs[2], attrs[3]);
canvas.drawRoundRect(rectF, attrs[4], attrs[4], paint);
}
private void drawRoundRectStroke(Canvas canvas, int color) {
int sw = dp2px(DEFAULT_WIDTH);
int sh = dp2px(DEFAULT_HEIGHT);
float left = dp2pxFloat((float) 2.4);
float right = sw - left;
float top = dp2pxFloat((float) 2.4);
float bottom = sh - top;
float radius = (bottom - top) * 0.5f;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(color);
paint.setStrokeWidth(dp2pxFloat((float) 3.6));
RectF rectF = new RectF();
rectF.set(left, top, right, bottom);
canvas.drawRoundRect(rectF, radius, radius, paint);
}
private void drawOvalIn(Canvas canvas, int color, float[] attrs) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(color);
int borderWidth = dp2px(DEFAULT_BORDER_WIDTH);
RectF rectFIn = new RectF(attrs[0] + borderWidth, attrs[1] + borderWidth, attrs[2] - borderWidth, attrs[3] - borderWidth);
canvas.drawOval(rectFIn, paint);
}
private void drawOval(Canvas canvas, int color, float[] attrs) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(color);
RectF rectF = new RectF(attrs[0], attrs[1], attrs[2], attrs[3]);
canvas.drawOval(rectF, paint);
}
private float[] compRoundRectAttr(float pos) {
int sw = dp2px(DEFAULT_WIDTH);
int sh = dp2px(DEFAULT_HEIGHT);
float left = sw * pos;
float right = sw - left;
float top = sh * pos;
float bottom = sh - top;
float radius = (bottom - top) * 0.5f;
return new float[]{left, top, right, bottom, radius};
}
private float[] compRoundRectShadeOnAttr(float pos) {
int sw = dp2px(DEFAULT_WIDTH);
int sh = dp2px(DEFAULT_HEIGHT);
int oh = sh - 2 * spotPadding;
float left, right, top, bottom;
if(pos < 0.35){
left = 0;
right = spotPadding + (sw - sh) * pos + oh;
top = spotPadding;
bottom = oh + top;
}else{
left = spotPadding + (sw - sh) * pos *2/3;
right = spotPadding + (sw - sh) * pos *2/3+ oh;
top = spotPadding;
bottom = oh + top;
}
float radius = (bottom - top) * 0.5f;
return new float[]{left, top, right, bottom, radius};
}
private float[] compRoundRectShadeOffAttr(float pos) {
int sw = dp2px(DEFAULT_WIDTH);
int sh = dp2px(DEFAULT_HEIGHT);
int oh = sh - 2 * spotPadding;
float left, right, top, bottom;
if(pos > 0.65){
left = spotPadding + (sw - sh) * pos;
right = sw - spotPadding;
top = spotPadding;
bottom = oh + top;
}else{
left = spotPadding + (sw - sh) * (2*pos + 1)/3;
right = spotPadding + (sw - sh) * (2*pos + 1)/3 + oh;
top = spotPadding;
bottom = oh + top;
}
float radius = (bottom - top) * 0.5f;
return new float[]{left, top, right, bottom, radius};
}
private float[] compOvalAttr(float pos) {
if(pos > 1){
pos = 1;
}
int sw = dp2px(DEFAULT_WIDTH);
int sh = dp2px(DEFAULT_HEIGHT);
int oh = sh - 2 * spotPadding;
float left = spotPadding + (sw - sh) * pos;
float right = left + oh;
float top = spotPadding;
float bottom = oh + top;
return new float[]{left, top, right, bottom};
}
private int compColor(float fraction, int startColor, int endColor) {
return (Integer) new ArgbEvaluator().evaluate(fraction, startColor, endColor);
}
#Override
public boolean performClick() {
toggle();
final boolean handled = super.performClick();
if (!handled) {
// View only makes a sound effect if the onClickListener was
// called, so we'll need to make one here instead.
playSoundEffect(SoundEffectConstants.CLICK);
}
return handled;
}
public int dp2px(float dpValue) {
float scale = getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public float dp2pxFloat(float dpValue) {
float scale = getResources().getDisplayMetrics().density;
return dpValue * scale + 0.5f;
}
#TargetApi(Build.VERSION_CODES.KITKAT)
#Override
public void setChecked(boolean checked) {
if (isMoving) {
return;
}
if (mChecked != checked) {
mChecked = checked;
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
return;
}
mBroadcasting = true;
if (onCheckedChangeListener != null) {
onCheckedChangeListener.onCheckedChanged(this, mChecked);
}
mBroadcasting = false;
if (mChecked) {
state = State.SWITCH_ANIMATION_ON;
} else {
state = State.SWITCH_ANIMATION_OFF;
}
if (isAttachedToWindow() && isLaidOut()) {
animateToCheckedState();
} else {
// Immediately move the thumb to the new position.
cancelPositionAnimator();
currentPos = 0;
}
}
}
private void cancelPositionAnimator() {
if (valueAnimator != null) {
valueAnimator.cancel();
}
}
private void animateToCheckedState() {
valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(duration);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPos = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
isMoving = true;
}
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isMoving = false;
}
});
if (!valueAnimator.isRunning()) {
valueAnimator.start();
currentPos = 0;
}
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
#Override
public boolean isChecked() {
return mChecked;
}
#Override
public void toggle() {
setChecked(!mChecked);
}
public int getSwitchOnColor() {
return switchOnColor;
}
public void setSwitchOnColor(#ColorInt int switchOnColor) {
this.switchOnColor = switchOnColor;
invalidate();
}
public int getSwitchOffColor() {
return switchOffColor;
}
public void setSwitchOffColor(#ColorInt int switchOffColor) {
this.switchOffColor = switchOffColor;
invalidate();
}
public int getSpotOnColor() {
return spotOnColor;
}
public void setSpotOnColor(#ColorInt int spotOnColor) {
this.spotOnColor = spotOnColor;
invalidate();
}
public int getSpotOffColor() {
return spotOffColor;
}
public void setSpotOffColor(#ColorInt int spotOffColor) {
this.spotOffColor = spotOffColor;
invalidate();
}
public int getSpotPadding() {
return spotPadding;
}
public void setSpotPadding(int spotPadding) {
this.spotPadding = spotPadding;
invalidate();
}
public int getSwitchOffStrokeColor() {
return switchOffStrokeColor;
}
public void setSwitchOffStrokeColor(int switchOffStrokeColor) {
this.switchOffStrokeColor = switchOffStrokeColor;
invalidate();
}
public int getSwitchOnStrokeColor() {
return switchOnStrokeColor;
}
public void setSwitchOnStrokeColor(int switchOnStrokeColor) {
this.switchOnStrokeColor = switchOnStrokeColor;
invalidate();
}
public OnCheckedChangeListener getOnCheckedChangeListener() {
return onCheckedChangeListener;
}
public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
this.onCheckedChangeListener = onCheckedChangeListener;
}
public interface OnCheckedChangeListener {
/**
* Called when the checked state of a switch has changed.
*
* #param s The switch whose state has changed.
* #param isChecked The new checked state of switch.
*/
void onCheckedChanged(MySwitchButton s, boolean isChecked);
}
}
You need to set value in preferences when the switch state is changed,
switchButton.setOnCheckedChangeListener(new MySwitchButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(MySwitchButton s, boolean isChecked) {
setPreference(context,ischecked);
//your code
}
});
EDIT:
In your oncreate() method, use
switchButton.setChecked(getPreference());
And directly return value in getPreference() method as,
public boolean getPreference() {
SharedPreferences settings = this.getSharedPreferences("sharedPref", Context.MODE_PRIVATE);
// Toast.makeText(this,"EMP ID is "+emp_id,Toast.LENGTH_LONG).show();
Common.punchedIn = settings.getBoolean("punch", false);
Toast.makeText(this,"PUNCH IN STATUS "+String.valueOf(Common.punchedIn),Toast.LENGTH_LONG).show();
return Common.punchedIn;
}
Replace your onCreate code with this, after retrieve the shared-preference data:
switchButton.post(new Runnable() {
#Override
public void run() {
if(Common.punchedIn) {
switchButton.setChecked(false);
}
else {
switchButton.setChecked(true);
}
}
});
For all those facing similar issues this is how I did it
There are static int variables in MySwitchButton class and I just swapped the position.Its now working fine
getPreference();
if (Common.punchedIn) {
switchButton.setOnCheckedChangeListener(null);
//switchButton.setChecked(false);
punchStatus_text.setText("Punch Out");
MySwitchButton.SWITCH_OFF_POS=1;
MySwitchButton.SWITCH_ON_POS=0;
//setColorPreference(AttendanceActivity.this,Color.GREEN,Color.RED);
} else {
switchButton.setOnCheckedChangeListener(null);
//switchButton.setChecked(true);
punchStatus_text.setText("Punch In");
MySwitchButton.SWITCH_OFF_POS=0;
MySwitchButton.SWITCH_ON_POS=1;
//setColorPreference(AttendanceActivity.this,Color.RED,Color.GREEN);
}
Try using handlers that check value after some interval and accordingly change the state of the switch automatically to checked or unchecked.
new Handler().postDelayed(new Runnable()
{ public void run()
{ runOnUiThread(new Runnable()
{ public void run() {
if(check) {
aSwitch.setChecked(true);
}
else {
aSwitch.setChecked(false);
}
} }); } }, 5000);

Viewpager: Too small indicator or too much tabs?

Im using a ViewPager to show Images. The ViewPager is working correctly but there is an error with the indicator. When i swipe to the very last entry the indicator is only at round about 70% of the way. See the screen:
That is the problem. I dont know if the indicator is just too small, moving to slow or there are another hidden entries in the viewpager but since i cant swipe any further to the right i guess there is a bug with the indicator size or moving or something like that.
This is how i initializ my viewpager:
this.viewPager.setId(R.id.image_inspiration_pager);
this.viewPager.setClipToPadding(false);
this.viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(this.getContext(), 48)), 0);
this.viewPager.setAdapter(adapter);
this.viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
private static final float thresholdOffset = 0.5f;
private boolean scrollStarted = false;
private boolean checkDirection = false;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (position == 0) {
viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0);
return;
} else if (position == (adapter.getCount() - 1)) {
viewPager.setPadding(((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0, 0, 0);
return;
}
if (this.checkDirection) {
if (thresholdOffset > positionOffset) {
viewPager.setPadding(0, 0, ((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0);
} else {
viewPager.setPadding(((int) HelperPixel.convertDpToPixel(getContext(), 48)), 0, 0, 0);
}
this.checkDirection = false;
}
}
#Override
public void onPageSelected(int position) {}
#Override
public void onPageScrollStateChanged(int state) {
if (!this.scrollStarted && state == ViewPager.SCROLL_STATE_DRAGGING) {
this.scrollStarted = true;
this.checkDirection = true;
} else {
this.scrollStarted = false;
}
}
});
Implementation of TabLayout:
public class TabsSlidingLayout extends HorizontalScrollView {
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TAB_VIEW_PADDING_DIPS = 16;
private static final int TAB_VIEW_TEXT_SIZE_SP = 14;
private int titleOffset;
private int tabViewLayoutId;
private int tabViewTextViewId;
private ViewPager viewPager;
private ViewPager.OnPageChangeListener pageChangeListener;
private final TabsSlidingStrip tabStrip;
public TabsSlidingLayout(Context context) {
this(context, null);
}
public TabsSlidingLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TabsSlidingLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setHorizontalScrollBarEnabled(false);
this.setFillViewport(true);
this.titleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
this.tabStrip = new TabsSlidingStrip(context);
this.addView(this.tabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
public void setCustomBackgroundColor(int color) {
this.tabStrip.setBackgroundColor(color);
}
public void setCustomTabColorizer(TabColorizer tabColorizer) {
this.tabStrip.setCustomTabColorizer(tabColorizer);
}
public void setSelectedIndicatorColors(int... colors) {
this.tabStrip.setSelectedIndicatorColors(colors);
}
public void setDividerColors(int... colors) {
this.tabStrip.setDividerColors(colors);
}
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
this.pageChangeListener = listener;
}
public void setCustomTabView(int layoutResId, int textViewId) {
this.tabViewLayoutId = layoutResId;
this.tabViewTextViewId = textViewId;
}
public void setViewPager(ViewPager viewPager) {
this.tabStrip.removeAllViews();
this.viewPager = viewPager;
if (this.viewPager != null) {
this.viewPager.addOnPageChangeListener(new InternalViewPagerListener());
this.populateTabStrip();
}
}
protected TextView createDefaultTabView(Context context) {
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setTextColor(ContextCompat.getColor(context, R.color.white));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
TypedValue outValue = new TypedValue();
this.getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
textView.setBackgroundResource(outValue.resourceId);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
textView.setAllCaps(true);
}
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
textView.setPadding(padding, padding, padding, padding);
return textView;
}
private void populateTabStrip() {
final PagerAdapter adapter = this.viewPager.getAdapter();
final View.OnClickListener tabClickListener = new TabClickListener();
for (int i = 0; i < adapter.getCount(); i++) {
View tabView = null;
TextView tabTitleView = null;
if (this.tabViewLayoutId != 0) {
tabView = LayoutInflater.from(this.getContext()).inflate(this.tabViewLayoutId, this.tabStrip, false);
tabTitleView = (TextView) tabView.findViewById(this.tabViewTextViewId);
}
if (tabView == null) {
tabView = createDefaultTabView(this.getContext());
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
tabTitleView.setText(adapter.getPageTitle(i));
tabView.setOnClickListener(tabClickListener);
this.tabStrip.addView(tabView);
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (this.viewPager != null) {
this.scrollToTab(this.viewPager.getCurrentItem(), 0);
}
}
private void scrollToTab(int tabIndex, int positionOffset) {
final int tabStripChildCount = this.tabStrip.getChildCount();
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
return;
}
View selectedChild = this.tabStrip.getChildAt(tabIndex);
if (selectedChild != null) {
int targetScrollX = selectedChild.getLeft() + positionOffset;
if (tabIndex > 0 || positionOffset > 0) {
targetScrollX -= this.titleOffset;
}
this.scrollTo(targetScrollX, 0);
}
}
public interface TabColorizer {
int getIndicatorColor(int position);
int getDividerColor(int position);
}
private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
private int scrollState = -1;
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
int tabStripChildCount = tabStrip.getChildCount();
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
return;
}
tabStrip.onViewPagerPageChanged(position, positionOffset);
View selectedTitle = tabStrip.getChildAt(position);
int extraOffset = (selectedTitle != null) ? (int) (positionOffset * selectedTitle.getWidth()) : 0;
scrollToTab(position, extraOffset);
if (pageChangeListener != null) {
pageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
#Override
public void onPageScrollStateChanged(int state) {
this.scrollState = state;
if (pageChangeListener != null) {
pageChangeListener.onPageScrollStateChanged(state);
}
}
#Override
public void onPageSelected(int position) {
if (this.scrollState == ViewPager.SCROLL_STATE_IDLE) {
tabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
if (pageChangeListener != null) {
pageChangeListener.onPageSelected(position);
}
}
}
private class TabClickListener implements View.OnClickListener {
#Override
public void onClick(View view) {
for (int i = 0; i < tabStrip.getChildCount(); i++) {
if (view == tabStrip.getChildAt(i)) {
viewPager.setCurrentItem(i);
return;
}
}
}
}
}
TabSlidingStrip implementation:
class TabsSlidingStrip extends LinearLayout {
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0;
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 2;
private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFFFFFFFF;
private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 0;
private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
private static final float DEFAULT_DIVIDER_HEIGHT = 0.0f;
private final int bottomBorderThickness;
private final Paint bottomBorderPaint;
private final int selectedIndicatorThickness;
private final Paint selectedIndicatorPaint;
private final Paint dividerPaint;
private final float dividerHeight;
private int selectedPosition;
private float selectionOffset;
private TabsSlidingLayout.TabColorizer customTabColorizer;
private final SimpleTabColorizer defaultTabColorizer;
public TabsSlidingStrip(Context context) {
this(context, null);
}
public TabsSlidingStrip(Context context, AttributeSet attrs) {
super(context, attrs);
this.setWillNotDraw(false);
final float density = getResources().getDisplayMetrics().density;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);
final int themeForegroundColor = outValue.data;
this.setBackgroundColor(ContextCompat.getColor(context, R.color.primaryColor));
this.defaultTabColorizer = new SimpleTabColorizer();
this.defaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
this.defaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA));
this.bottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
this.bottomBorderPaint = new Paint();
this.bottomBorderPaint.setColor(setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA));
this.selectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
this.selectedIndicatorPaint = new Paint();
this.dividerHeight = DEFAULT_DIVIDER_HEIGHT;
this.dividerPaint = new Paint();
this.dividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
}
void setCustomTabColorizer(TabsSlidingLayout.TabColorizer customTabColorizer) {
this.customTabColorizer = customTabColorizer;
this.invalidate();
}
void setSelectedIndicatorColors(int... colors) {
this.customTabColorizer = null;
this.defaultTabColorizer.setIndicatorColors(colors);
this.invalidate();
}
void setDividerColors(int... colors) {
this.customTabColorizer = null;
this.defaultTabColorizer.setDividerColors(colors);
this.invalidate();
}
void onViewPagerPageChanged(int position, float positionOffset) {
this.selectedPosition = position;
this.selectionOffset = positionOffset;
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
final int height = this.getHeight();
final int childCount = this.getChildCount();
final int dividerHeightPx = (int) (Math.min(Math.max(0f, this.dividerHeight), 1f) * height);
final TabsSlidingLayout.TabColorizer tabColorizer = this.customTabColorizer != null ? this.customTabColorizer : this.defaultTabColorizer;
if (childCount > 0) {
View selectedTitle = getChildAt(this.selectedPosition);
int left = selectedTitle.getLeft();
int right = selectedTitle.getRight();
int color = tabColorizer.getIndicatorColor(this.selectedPosition);
if (this.selectionOffset > 0f && this.selectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(this.selectedPosition + 1);
if (color != nextColor) {
color = blendColors(nextColor, color, this.selectionOffset);
}
View nextTitle = getChildAt(this.selectedPosition + 1);
left = (int) (this.selectionOffset * nextTitle.getLeft() + (1.0f - this.selectionOffset) * left);
right = (int) (this.selectionOffset * nextTitle.getRight() + (1.0f - this.selectionOffset) * right);
}
this.selectedIndicatorPaint.setColor(color);
canvas.drawRect(left, height - this.selectedIndicatorThickness, right, height, this.selectedIndicatorPaint);
}
canvas.drawRect(0, height - this.bottomBorderThickness, this.getWidth(), height, this.bottomBorderPaint);
int separatorTop = (height - dividerHeightPx) / 2;
for (int i = 0; i < childCount - 1; i++) {
View child = getChildAt(i);
this.dividerPaint.setColor(tabColorizer.getDividerColor(i));
canvas.drawLine(child.getRight(), separatorTop, child.getRight(), separatorTop + dividerHeightPx, this.dividerPaint);
}
}
private static int setColorAlpha(int color, byte alpha) {
return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
}
private static int blendColors(int color1, int color2, float ratio) {
final float inverseRation = 1f - ratio;
float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
return Color.rgb((int) r, (int) g, (int) b);
}
private static class SimpleTabColorizer implements TabsSlidingLayout.TabColorizer {
private int[] indicatorColors;
private int[] dividerColors;
#Override
public final int getIndicatorColor(int position) {
return this.indicatorColors[position % this.indicatorColors.length];
}
void setIndicatorColors(int... colors) {
this.indicatorColors = colors;
}
#Override
public final int getDividerColor(int position) {
return this.dividerColors[position % this.dividerColors.length];
}
void setDividerColors(int... colors) {
this.dividerColors = colors;
}
}
}
The first screenshot is from a tablet. Here is a screen from my smartphone:
As you can see for the smartphone the gap is much smaller than on the tablet.
Any idea what could be the problem?
Add the following code to the bottom of createDefaultTabView:
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
textView.setWidth(size.x / this.viewPager.getAdapter().getCount());

How can I place the icons on the top of the circular image in Android?

I just want to achieve exactly what is on the above image. Red are my icons where I need to place that on the top of the circular image borders. Each and every red icons have its own function. Say they are kind of rating buttons. How can I make a XML design to achieve this?
The exact solution for your problem would be the use of Circular Positioning in ConstraintLayout and for more information about it you may follow this link:
https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html#CircularPositioning
Hope this would entirely solve your problem and thereby help you build your desired UI.
Take a look on this class. It should works as you want :
public class CircleLayout extends ViewGroup {
private static final float DEFAULT_FROM_DEGREES = -90f;
private static final float DEFAULT_TO_DEGREES = 270f;
private static final int MIN_RADIUS_DP = 100;
private static final float DEFAULT_CHILD_PADDING_DP = 5f;
private final Rect tempChildFrame = new Rect();
private final float fromDegrees;
private final float toDegrees;
private final int childPadding;
private final int minRadius;
private int radius;
private int childSize;
private boolean expanded;
public CircleLayout(Context context) {
this(context, null);
}
public CircleLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleLayout(Context context, AttributeSet attrs, int def) {
super(context, attrs);
final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircleLayout, 0, 0);
try {
childSize = Math.max(a.getDimensionPixelSize(R.styleable.CircleLayout_childSize, 0), 0);
fromDegrees = a.getFloat(R.styleable.CircleLayout_fromDegrees, DEFAULT_FROM_DEGREES);
toDegrees = a.getFloat(R.styleable.CircleLayout_toDegrees, DEFAULT_TO_DEGREES);
final float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CHILD_PADDING_DP, getResources().getDisplayMetrics());
childPadding = (int) a.getDimension(R.styleable.CircleLayout_childPadding, px);
expanded = a.getBoolean(R.styleable.CircleLayout_expandedChild, true);
minRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, MIN_RADIUS_DP, getResources().getDisplayMetrics());
} finally {
a.recycle();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
radius = computeRadius(Math.abs(toDegrees - fromDegrees), getChildCount(), childSize, childPadding, minRadius);
final int size = radius * 2 + childSize + childPadding;
setMeasuredDimension(size + getPaddingLeft() + getPaddingRight(), size + getPaddingTop() + getPaddingBottom());
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(childSize, MeasureSpec.EXACTLY));
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int centerX = getWidth() / 2;
final int centerY = getHeight() / 2;
final int radius = expanded ? this.radius : 0;
final int childCount = getChildCount();
final float perDegrees = (toDegrees - fromDegrees) / childCount;
float degrees = fromDegrees;
for (int i = 0; i < childCount; i++) {
computeChildFrame(centerX, centerY, radius, degrees, childSize, tempChildFrame);
degrees += perDegrees;
getChildAt(i).layout(tempChildFrame.left, tempChildFrame.top, tempChildFrame.right, tempChildFrame.bottom);
}
}
private int computeRadius(float arcDegrees, int childCount, int childSize, int childPadding, int minRadius) {
if (childCount < 2) {
return minRadius;
}
final float perDegrees = arcDegrees / childCount;
final float perHalfDegrees = perDegrees / 2;
final int perSize = childSize + childPadding;
final int radius = (int) ((perSize / 2) / Math.sin(Math.toRadians(perHalfDegrees)));
return Math.max(radius, minRadius);
}
private void computeChildFrame(int centerX, int centerY, int radius, float degrees, int size, Rect result) {
final double childCenterX = centerX + radius * Math.cos(Math.toRadians(degrees));
final double childCenterY = centerY + radius * Math.sin(Math.toRadians(degrees));
final float halfSize = size * .5f;
result.left = (int) (childCenterX - halfSize);
result.top = (int) (childCenterY - halfSize);
result.right = (int) (childCenterX + halfSize);
result.bottom = (int) (childCenterY + halfSize);
}
public void expand() {
expanded = true;
requestLayout();
}
public void shrink() {
expanded = false;
requestLayout();
}
public void setChildSize(int size) {
if (childSize == size || size < 0) {
return;
}
childSize = size;
requestLayout();
}
public boolean isExpanded() {
return expanded;
}
#Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
final SavedState result = new SavedState(superState);
result.childSize = childSize;
result.expanded = expanded;
return result;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
final SavedState ss = (SavedState) state;
childSize = ss.childSize;
expanded = ss.expanded;
super.onRestoreInstanceState(ss.getSuperState());
}
public static class SavedState extends BaseSavedState {
#SuppressWarnings("hiding")
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
private int childSize;
private boolean expanded;
SavedState(Parcelable superState) {
super(superState);
}
#Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(childSize);
out.writeInt(expanded ? 1 : 0);
}
private SavedState(Parcel in) {
super(in);
childSize = in.readInt();
expanded = in.readInt() != 0;
}
}
}
You also have to add style for this view :
<declare-styleable name="CircleLayout">
<attr name="childSize" format="dimension"/>
<attr name="childPadding" format="dimension"/>
<attr name="fromDegrees" format="integer"/>
<attr name="toDegrees" format="integer"/>
<attr name="expandedChild" format="boolean"/>
</declare-styleable>
Example using:
<your.package.CircleLayout
android:clipChildren="false"
android:id="#+id/test_circle_view"
android:layout_width="match_parent"
app:childSize="50dp"
app:childPadding="25dp"
app:expandedChild="true"
android:layout_height="match_parent">
<ImageView
android:id="#+id/circle_item_1"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/some_circle"/>
<ImageView
android:id="#+id/circle_item_2"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/some_circle"/>
<ImageView
android:id="#+id/circle_item_3"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/some_circle"/>
<ImageView
android:id="#+id/circle_item_4"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/some_circle"/>
<ImageView
android:id="#+id/circle_item_5"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/some_circle"/>
<ImageView
android:id="#+id/circle_item_6"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#drawable/some_circle"/>
</your.package.CircleLayout>

How to auto adjust the font size of a spinner based on its longest value in android

I have a spinner in which I want to display several names.
I get the names based on a sqlite query. How I can reduce font size based on the length of the longest name? Shall I use and check with
textView.getText().length() ?
Naive:
Find longest string.
Measure TextView Max size.
Measure
text to fit inside TextView. (Using TextPaint, that provides measure text methods.)
You just need to figure out algorithm. Could be something like this.
size = TextView.getWidth();
paint = new TextPaint();
paint.setTextSize(SOME_BIG_NUMBER);
while(true){
if (paint.measureText(longest_text) < size){
break;
} else {
paint.setTextSize(paint.getTextSize() -1f);
}
}
result size = paint.getTextSize();
Another approach could be using AutoResizeTextView. After setting data, just go thru all AutoResizeTextViews, find minimum, then set it to all TextViews. But it's extremely expensive and user will notice drawing.
public class AutoResizeTextView extends TextView {
private interface SizeTester {
/**
* #param suggestedSize Size of text to be tested
* #param availableSpace available space in which text must fit
*
* #return an integer < 0 if after applying {#code suggestedSize} to
* text, it takes less space than {#code availableSpace}, > 0
* otherwise
*/
public int onTestSize(int suggestedSize, RectF availableSpace);
}
private RectF mTextRect = new RectF();
private RectF mAvailableSpaceRect;
private SparseIntArray mTextCachedSizes;
private TextPaint mPaint;
private float mMaxTextSize;
private float mSpacingMult = 1.0f;
private float mSpacingAdd = 0.0f;
private float mMinTextSize = 20;
private int mWidthLimit;
private Typeface mTypeFace;
private static final int NO_LINE_LIMIT = -1;
private int mMaxLines;
private boolean mEnableSizeCache = true;
private boolean mInitiallized;
public AutoResizeTextView(Context context) {
super(context);
initialize();
ArrayList<String> list = new ArrayList<>();
int index = -1;
for (String st : list) {
index = index < st.length() ? st.length() :index;
}
TextPaint paint = new TextPaint();
paint.measureText(list.get(index));
}
public AutoResizeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize();
}
private void initialize() {
mPaint = new TextPaint(getPaint());
if (mTypeFace != null) {
mPaint.setTypeface(mTypeFace);
}
mMaxTextSize = getTextSize();
mAvailableSpaceRect = new RectF();
mTextCachedSizes = new SparseIntArray();
if (mMaxLines == 0) {
// no value was assigned during construction
mMaxLines = NO_LINE_LIMIT;
}
mInitiallized = true;
}
#Override
public void setText(final CharSequence text, BufferType type) {
super.setText(text, type);
adjustTextSize(text.toString());
}
#Override
public void setTextSize(float size) {
mMaxTextSize = size;
mTextCachedSizes.clear();
adjustTextSize(getText().toString());
}
#Override
public void setMaxLines(int maxlines) {
super.setMaxLines(maxlines);
mMaxLines = maxlines;
reAdjust();
}
public int getMaxLines() {
return mMaxLines;
}
#Override
public void setSingleLine() {
super.setSingleLine();
mMaxLines = 1;
reAdjust();
}
#Override
public void setSingleLine(boolean singleLine) {
super.setSingleLine(singleLine);
if (singleLine) {
mMaxLines = 1;
} else {
mMaxLines = NO_LINE_LIMIT;
}
reAdjust();
}
#Override
public void setLines(int lines) {
super.setLines(lines);
mMaxLines = lines;
reAdjust();
}
#Override
public void setTextSize(int unit, float size) {
Context c = getContext();
Resources r;
if (c == null) {
r = Resources.getSystem();
} else {
r = c.getResources();
}
mMaxTextSize = TypedValue.applyDimension(unit, size,
r.getDisplayMetrics());
mTextCachedSizes.clear();
adjustTextSize(getText().toString());
}
#Override
public void setLineSpacing(float add, float mult) {
super.setLineSpacing(add, mult);
mSpacingMult = mult;
mSpacingAdd = add;
}
/**
* Set the lower text size limit and invalidate the view
*
* #param minTextSize
*/
public void setMinTextSize(float minTextSize) {
mMinTextSize = minTextSize;
reAdjust();
}
private void reAdjust() {
adjustTextSize(getText().toString());
}
private void adjustTextSize(String string) {
if (!mInitiallized) {
return;
}
int startSize = (int) mMinTextSize;
int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom()
- getCompoundPaddingTop();
mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft()
- getCompoundPaddingRight();
if (mWidthLimit < 0) {
mWidthLimit = 0;
}
mAvailableSpaceRect.right = mWidthLimit;
mAvailableSpaceRect.bottom = heightLimit;
super.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
efficientTextSizeSearch(startSize, (int) mMaxTextSize,
mSizeTester, mAvailableSpaceRect));
}
private final SizeTester mSizeTester = new SizeTester() {
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public int onTestSize(int suggestedSize, RectF availableSPace) {
mPaint.setTextSize(suggestedSize);
String text = getText().toString();
boolean singleline = getMaxLines() == 1;
if (singleline) {
mTextRect.bottom = mPaint.getFontSpacing();
mTextRect.right = mPaint.measureText(text);
} else {
StaticLayout layout = new StaticLayout(text, mPaint,
mWidthLimit, Layout.Alignment.ALIGN_NORMAL, mSpacingMult,
mSpacingAdd, true);
// return early if we have more lines
if (getMaxLines() != NO_LINE_LIMIT
&& layout.getLineCount() > getMaxLines()) {
return 1;
}
mTextRect.bottom = layout.getHeight();
int maxWidth = -1;
for (int i = 0; i < layout.getLineCount(); i++) {
if (maxWidth < layout.getLineWidth(i)) {
maxWidth = (int) layout.getLineWidth(i);
}
}
mTextRect.right = maxWidth;
}
mTextRect.offsetTo(0, 0);
if (availableSPace
.contains(mTextRect)) { // may be too small, don't worry we will find the best match
return -1;
} else {
if (mTextRect.bottom < availableSPace.bottom
&& mTextRect.right > availableSPace.right) {
// hack :O
return -1;
}
// too big
return 1;
}
}
};
/**
* Enables or disables size caching, enabling it will improve performance
* where you are animating a value inside TextView. This stores the font
* size against getText().length() Be careful though while enabling it as 0
* takes more space than 1 on some fonts and so on.
*
* #param enable enable font size caching
*/
public void enableSizeCache(boolean enable) {
mEnableSizeCache = enable;
mTextCachedSizes.clear();
adjustTextSize(getText().toString());
}
private int efficientTextSizeSearch(int start, int end,
SizeTester sizeTester, RectF availableSpace) {
if (!mEnableSizeCache) {
return binarySearch(start, end, sizeTester, availableSpace);
}
String text = getText().toString();
int key = text == null ? 0 : text.length();
int size = mTextCachedSizes.get(key);
if (size != 0) {
return size;
}
size = binarySearch(start, end, sizeTester, availableSpace);
mTextCachedSizes.put(key, size);
return size;
}
private static int binarySearch(int start, int end, SizeTester sizeTester,
RectF availableSpace) {
int lastBest = start;
int lo = start;
int hi = end - 1;
int mid = 0;
while (lo <= hi) {
mid = (lo + hi) >>> 1;
int midValCmp = sizeTester.onTestSize(mid, availableSpace);
if (midValCmp < 0) {
lastBest = lo;
lo = mid + 1;
} else if (midValCmp > 0) {
hi = mid - 1;
lastBest = hi;
} else {
return mid;
}
}
// make sure to return last best
// this is what should always be returned
return lastBest;
}
#Override
protected void onTextChanged(final CharSequence text, final int start,
final int before, final int after) {
super.onTextChanged(text, start, before, after);
reAdjust();
}
#Override
protected void onSizeChanged(int width, int height, int oldwidth,
int oldheight) {
mTextCachedSizes.clear();
super.onSizeChanged(width, height, oldwidth, oldheight);
if (width != oldwidth || height != oldheight) {
reAdjust();
}
}
#Override
public void setTypeface(Typeface tf) {
super.setTypeface(tf);
mTypeFace = tf;
if (mInitiallized) {
mPaint.setTypeface(tf);
mTextCachedSizes.clear();
reAdjust();
}
}
#Override
public CharSequence getAccessibilityClassName() {
return TextView.class.getName();
}
}
Best approach is to combine these approaches. Find longest text. Simplify the AutoResizeTextView to only calculate textSize. Set this size to you textViews.

Categories

Resources