i`m trying to use the AutoResizeTextView class like discussed here:
enter link description here
But if i do
textview.setMaxLines(1);
the text doesnt stay vertically centered. Its only horizontally centered. If i do:
textview.setMaxLines(2);
it works, but i need only one line.
i`m using exactly this class:
package com.example.myapp;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Build;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.widget.TextView;
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 static final int NO_LINE_LIMIT = -1;
private int mMaxLines;
private boolean mEnableSizeCache = true;
private boolean mInitiallized;
public AutoResizeTextview(Context context) {
super(context);
initialize();
}
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());
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();
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, 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 {
// 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();
}
}
}
UPDATE
changing the anonymous class "private final SizeTester mSizeTester = new SizeTester()" like:
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) { //my comment-out
// mTextRect.bottom = mPaint.getFontSpacing(); //my comment-out
// mTextRect.right = mPaint.measureText(text); //my comment-out
// } else { //my comment-out
StaticLayout layout = new StaticLayout(text, mPaint, mWidthLimit, 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;
// } //my comment-out
mTextRect.offsetTo(0, 0);
if (availableSPace.contains(mTextRect))
{
// may be too small, don't worry we will find the best match
return -1;
}
else
{
// too big
return 1;
}
}
};
....solves it. See the Lines with "my comment-out" at the end. Not sure if there are any negative side-effects though yet.
Related
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);
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());
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.
am looking to create a customs slider component with the functionality of s seek bar.
I have been following this tutorial
http://www.androidenea.com/2011/10/creating-custom-view-part-1-graphics.html
however, I wish to use my own graphics which aren't .9.png graphics. I also need to resize the seek bar and the slider.
If anyone can help on this I'd greatly appreciate it. I have it to a stage where I have it resized and the graphics are changed however, when I use my finger to slide upwards I need to slide to the top of the screen in order for my seebar to reach the top of the frame.
Please any help is appreciated, this is what I've implemented so far:
package com.enea.training.customview;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CustomSlider extends View {
interface CustomSliderPositionListener {
void onPositionChange(float newPosition);
}
private final Drawable mIndicator;
private final Drawable mBackground;
private float mMin;
private float mMax;
private float mPosition;
private Rect mViewRect;
private int mIndicatorOffset;
private int mIndicatorMaxPos;
private int mIndicatorMinPos;
private CustomSliderPositionListener mPositionListener;
private boolean mIsVertical;
public CustomSlider(final Context context) {
this(context, null, 0);
}
public CustomSlider(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomSlider(final Context context, final AttributeSet attrs,
final int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CustomSlider);
final int vertical = a.getInt(R.styleable.CustomSlider_orientation, 0);
mIsVertical = (vertical != 0);
final float max = a.getFloat(R.styleable.CustomSlider_max, 1.0f);
final float min = a.getFloat(R.styleable.CustomSlider_min, -1.0f);
setMinMax(min, max);
final Resources res = context.getResources();
if (mIsVertical) {
mIndicator = res.getDrawable(R.drawable.beer_with_arrows);
mBackground = res.getDrawable(R.drawable.glass);
} else {
mIndicator = res.getDrawable(R.drawable.indicator_horizontal);
mBackground = res.getDrawable(R.drawable.background_horizontal);
}
mPosition =(mMax - 1) ;/// 2 + mMin;
mPositionListener = null;
setOnTouchListener(new OnTouchListener() {
public boolean onTouch(final View v, final MotionEvent event) {
final float pos;
if (mIsVertical) {
float divisor = mIndicatorMinPos-mIndicatorMaxPos;
pos = (mMax - ((mMax - mMin) / divisor)
* event.getY());
} else {
pos = (mMin + ((mMax - mMin) / (mIndicatorMaxPos - mIndicatorMinPos))
* event.getX());
}
setPosition(pos);
return true;
}
});
}
#Override
protected void onDraw(final Canvas canvas) {
if (mViewRect == null) {
mViewRect = new Rect();
mViewRect.set(20,20,20,20);
getDrawingRect(mViewRect);
if (mIsVertical) {
mIndicatorOffset = mIndicator.getIntrinsicHeight();
mIndicatorMaxPos = mViewRect.top + mIndicatorOffset;
mIndicatorMinPos = mViewRect.bottom - mIndicatorOffset;
} else {
mIndicatorOffset = mIndicator.getIntrinsicWidth();
mIndicatorMaxPos = mViewRect.right - mIndicatorOffset;
mIndicatorMinPos = mViewRect.left + mIndicatorOffset;
}
mBackground.setBounds(mViewRect.left, mViewRect.top, mViewRect.right,
mViewRect.bottom);
}
final float pos;
final int left;
final int right;
final int top;
final int bottom;
if (mIsVertical) {
pos = mIndicatorMaxPos
+ ((mIndicatorMinPos - mIndicatorMaxPos) / (mMax - mMin))
* (mMax - mPosition);
left = mViewRect.centerX() - (mIndicator.getIntrinsicWidth() / 2);
top = (int) pos - (mBackground.getIntrinsicHeight() / 2);
} else {
pos = mIndicatorMinPos
+ ((mIndicatorMaxPos - mIndicatorMinPos) / (mMax - mMin))
* (mPosition - mMin);
left = (int) pos - (mIndicator.getIntrinsicWidth() / 2);
top = mViewRect.centerY() - (mIndicator.getIntrinsicHeight() / 2);
}
right = left + mIndicator.getIntrinsicWidth();
bottom = top + mIndicator.getIntrinsicHeight();
mIndicator.setBounds(left, top, right, bottom);
mIndicator.draw(canvas);
mBackground.draw(canvas);
}
#Override
protected void onMeasure(final int widthMeasureSpec,
final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mIsVertical) {
int desiredWidth = 100;
int desiredHeight = 100;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//MUST CALL THIS
setMeasuredDimension(width, height);
//setMeasuredDimension(getSuggestedMinimumWidth(),getSuggestedMinimumHeight());
// setMeasuredDimension(mIndicator.getIntrinsicWidth(), getMeasuredHeight());
} else {
setMeasuredDimension(getMeasuredWidth(), mBackground.getIntrinsicHeight());
}
}
public float getMin() {
return mMin;
}
public float getMax() {
return mMax;
}
public float getPosition() {
return mPosition;
}
public void setPosition(float position) {
position = within(position, mMin, mMax);
if (position != mPosition) {
mPosition = position;
invalidate();
if (mPositionListener != null) {
mPositionListener.onPositionChange(mPosition);
}
}
}
private static float within(float position, final float min, final float max) {
if (position < min) {
position = min;
}
if (position > max) {
position = max;
}
return position;
}
public void setMinMax(final float min, final float max) {
if ((min != mMin) || (max != mMax)) {
if (min > max) {
throw new IllegalArgumentException(
"setMinMax: min must be smaller than max.");
}
mMin = min;
mMax = max;
setPosition(mPosition);
invalidate();
}
}
public void setPositionListener(final CustomSliderPositionListener listener) {
mPositionListener = listener;
}
}
****EDIT****
So below I have done up a rough pic to show what I'm trying to do. So my custom view includes the slider, and frame (background and indicator). The slider (indicator) is dragged by user up and down inside the red background..
I would apprecaite any help and thank you for your help so far...
I
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