Is there a way to have a checkbox with a specific colour for the border when it's unchecked and then when it's checked to have a different colour for the border and a black tick without using images?
Thanks!
Try this...used the Materialcheckbox
MaterialCheckBox.java
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
public class MaterialCheckBox extends View {
private Paint paintBlue;
private Paint paintWithe;
private Paint paintCenter;
private int borderColor = Color.GRAY;
private int backgroundColor = Color.BLUE;
private int doneShapeColor = Color.WHITE;
private int baseWidth;
private int borderWidth;
private int width, height;
private float[] points = new float[8];
private int DURATION = 200;
private boolean checked;
private float correctProgress;
private boolean drawRecting;
private boolean isAnim;
private OnCheckedChangeListener listener;
private float padding;
public MaterialCheckBox(Context context) {
this(context, null);
}
public MaterialCheckBox(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MaterialCheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MaterialCheckBox(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
/**
* init
*
* #param context
*/
private void init(Context context) {
backgroundColor = getResources().getColor(R.color.dark_gray_app);
borderColor = getResources().getColor(R.color.dark_gray_app);
borderWidth = baseWidth = dp2px(2);
paintBlue = new Paint(Paint.ANTI_ALIAS_FLAG);
paintBlue.setColor(borderColor);
paintBlue.setStrokeWidth(borderWidth);
paintWithe = new Paint(Paint.ANTI_ALIAS_FLAG);
paintWithe.setColor(doneShapeColor);
paintWithe.setStrokeWidth(dp2px(2));
paintCenter = new Paint(Paint.ANTI_ALIAS_FLAG);
paintCenter.setColor(getResources().getColor(R.color.white));
paintCenter.setStrokeWidth(borderWidth);
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
setChecked(!isChecked());
}
});
drawRecting = true;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
height = width = Math.max(w, h);
points[0] = 101 / 378f * width;
points[1] = 0.5f * width;
points[2] = 163 / 378f * width;
points[3] = 251 / 378f * width;
points[4] = 149 / 378f * width;
points[5] = 250 / 378f * width;
points[6] = 278 / 378f * width;
points[7] = 122 / 378f * width;
padding = 57 / 378f * width;
}
/**
* draw checkbox
*
* #param canvas
*/
#Override
protected void onDraw(Canvas canvas) {
RectF rect = new RectF(padding, padding, width - padding, height - padding);
canvas.drawRoundRect(rect, baseWidth, baseWidth, paintBlue);
if (drawRecting) {
canvas.drawRect(padding + borderWidth, padding + borderWidth, width - padding - borderWidth, height - padding - borderWidth, paintCenter);
} else {
//画对号
if (correctProgress > 0) {
if (correctProgress < 1 / 3f) {
float x = points[0] + (points[2] - points[0]) * correctProgress;
float y = points[1] + (points[3] - points[1]) * correctProgress;
canvas.drawLine(points[0], points[1], x, y, paintWithe);
} else {
float x = points[4] + (points[6] - points[4]) * correctProgress;
float y = points[5] + (points[7] - points[5]) * correctProgress;
canvas.drawLine(points[0], points[1], points[2], points[3], paintWithe);
canvas.drawLine(points[4], points[5], x, y, paintWithe);
}
}
}
}
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
}
public void setDoneShapeColor(int doneShapeColor) {
this.doneShapeColor = doneShapeColor;
paintWithe.setColor(doneShapeColor);
}
public void setBorderColor(int borderColor) {
this.borderColor = borderColor;
}
public void setBorderWidth(int baseWidth) {
this.baseWidth = baseWidth;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
if (checked) {
showRect();
} else {
hideCorrect();
}
}
private void hideRect() {
if (isAnim) {
return;
}
isAnim = true;
drawRecting = true;
ValueAnimator va = ValueAnimator.ofFloat(0, 1).setDuration(DURATION);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float p = (float) animation.getAnimatedValue();
float c = 1f - p;
borderWidth = (int) (baseWidth + c * (width - baseWidth));
paintBlue.setColor(evaluate(c, borderColor, backgroundColor));
invalidate();
if (p >= 1) {
isAnim = false;
if (listener != null) {
checked = false;
listener.onCheckedChanged(MaterialCheckBox.this, checked);
}
}
}
});
va.start();
}
private void showRect() {
if (isAnim) {
return;
}
isAnim = true;
drawRecting = true;
ValueAnimator va = ValueAnimator.ofFloat(0, 1).setDuration(DURATION);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float p = (float) animation.getAnimatedValue();
borderWidth = (int) (10 + p * (width - 10));
paintBlue.setColor(evaluate(p, borderColor, backgroundColor));
invalidate();
if (p >= 1) {
isAnim = false;
drawRecting = false;
showCorrect();
}
}
});
va.start();
}
private void showCorrect() {
if (isAnim) {
return;
}
isAnim = true;
correctProgress = 0;
drawRecting = false;
ValueAnimator va = ValueAnimator.ofFloat(0, 1).setDuration(DURATION);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
correctProgress = (float) animation.getAnimatedValue();
invalidate();
if (correctProgress >= 1) {
isAnim = false;
if (listener != null) {
checked = true;
listener.onCheckedChanged(MaterialCheckBox.this, checked);
}
}
}
});
va.start();
}
private void hideCorrect() {
if (isAnim) {
return;
}
isAnim = true;
correctProgress = 1;
drawRecting = false;
ValueAnimator va = ValueAnimator.ofFloat(0, 1).setDuration(DURATION);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float p = (float) animation.getAnimatedValue();
correctProgress = 1f - p;
invalidate();
if (p >= 1) {
isAnim = false;
hideRect();
}
}
});
va.start();
}
public void setOnCheckedChangedListener(OnCheckedChangeListener listener) {
this.listener = listener;
}
interface OnCheckedChangeListener {
void onCheckedChanged(View view, boolean isChecked);
}
private int evaluate(float fraction, int startValue, int endValue) {
int startInt = startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return ((startA + (int) (fraction * (endA - startA))) << 24)
| ((startR + (int) (fraction * (endR - startR))) << 16)
| ((startG + (int) (fraction * (endG - startG))) << 8)
| ((startB + (int) (fraction * (endB - startB))));
}
public int dp2px(float value) {
final float scale = getContext().getResources().getDisplayMetrics().densityDpi;
return (int) (value * (scale / 160) + 0.5f);
}
}
Xml
<.MaterialCheckBox
android:id="#+id/chk_remember"
android:layout_width="45dp"
android:layout_height="45dp"
/>
Code
MaterialCheckBox checkbox=(MaterialCheckBox)findViewById(R.id.checkbox);
checkbox.setOnCheckedChangedListener(new MaterialCheckBox.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(View view, boolean isChecked) {
if(isChecked)
{
}
else
{
}
}
});
or try this https://github.com/navasmdc/MaterialDesignLibrary#checkbox
Related
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
}
}
I'm using this library from GitHub: https://github.com/lzyzsd/CircleProgress
I put ArcProgress into my MainLayout. I'm trying to change values on the progress bar but I cannot not see on screen. If I check with mArcProgress.getProgress(); this get me the right value, but the bar is empty in screen and doesn't show any progress.
I was trying using:
mArcProgress.invalidate();
but doesnt work.
The only way I found was with:
finish();
startActivity(getIntent());
but works not as I expected, because the full screen start and seems like a blink.
Anyone know how from another activity, changes this View and make possible to see the changes when setting mArcProgress.setProgress(aNumber); ?
this is ArcProgressFuel
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class ArcProgressFuel extends View {
private Paint paint;
private RectF rectF = new RectF();
private float strokeWidth;
public int progress;
private int max;
private int finishedStrokeColor;
private int unfinishedStrokeColor;
private float arcAngle;
Path path;
MainPageFragment mMainPageFragment;
public static int fuel_to_show;
private float arcBottomHeight;
private final int default_finished_color = Color.WHITE;
private final int default_unfinished_color = Color.rgb(72, 106, 176);
private final float default_suffix_padding;
private final float default_stroke_width;
private final int default_max = 100;
private final float default_arc_angle = 360 * 0.5f; //0.8 for speed, 0.5 for fuel
private float default_text_size;
private final int min_size;
private static final String INSTANCE_STATE = "saved_instance";
private static final String INSTANCE_STROKE_WIDTH = "stroke_width";
public static String instance_progress = "progress";
private static final String INSTANCE_MAX = "max";
private static final String INSTANCE_FINISHED_STROKE_COLOR = "finished_stroke_color";
private static final String INSTANCE_UNFINISHED_STROKE_COLOR = "unfinished_stroke_color";
private static final String INSTANCE_ARC_ANGLE = "arc_angle";
private static final String INSTANCE_SUFFIX = "suffix";
public ArcProgressFuel(Context context) {
this(context, null);
}
public ArcProgressFuel(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ArcProgressFuel(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
min_size = (int) Utils.dp2px(getResources(), 100);
default_suffix_padding = Utils.dp2px(getResources(), 4);
default_stroke_width = Utils.dp2px(getResources(), 4);
TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArcProgress, defStyleAttr, 0);
initByAttributes(attributes);
attributes.recycle();
initPainters();
}
protected void initByAttributes(TypedArray attributes) {
finishedStrokeColor = attributes.getColor(R.styleable.ArcProgress_arc_finished_color, default_finished_color);
unfinishedStrokeColor = attributes.getColor(R.styleable.ArcProgress_arc_unfinished_color, default_unfinished_color);
arcAngle = attributes.getFloat(R.styleable.ArcProgress_arc_angle, default_arc_angle);
setMax(attributes.getInt(R.styleable.ArcProgress_arc_max, default_max));
setProgress(attributes.getInt(R.styleable.ArcProgress_arc_progress, 0));
strokeWidth = attributes.getDimension(R.styleable.ArcProgress_arc_stroke_width, default_stroke_width);
fuel_to_show=mMainPageFragment.carFuel;
setProgress(fuel_to_show); //Aca puedo modificar el valor
}
protected void initPainters() {
paint = new Paint();
paint.setColor(default_unfinished_color);
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
}
/* #Override
public void invalidate() {
initPainters();
super.invalidate();
postInvalidate();
}*/
public float getStrokeWidth() {
return strokeWidth;
}
public void setStrokeWidth(float strokeWidth) {
this.strokeWidth = strokeWidth;
this.invalidate();
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
if (this.progress > getMax()) {
this.progress %= getMax();
}
invalidate();
}
public int getMax() {
return max;
}
public void setMax(int max) {
if (max > 0) {
this.max = max;
invalidate();
}
}
public int getFinishedStrokeColor() {
return finishedStrokeColor;
}
public void setFinishedStrokeColor(int finishedStrokeColor) {
this.finishedStrokeColor = finishedStrokeColor;
this.invalidate();
}
public int getUnfinishedStrokeColor() {
return unfinishedStrokeColor;
}
public void setUnfinishedStrokeColor(int unfinishedStrokeColor) {
this.unfinishedStrokeColor = unfinishedStrokeColor;
this.invalidate();
}
public float getArcAngle() {
return arcAngle;
}
public void setArcAngle(float arcAngle) {
this.arcAngle = arcAngle;
this.invalidate();
}
#Override
protected int getSuggestedMinimumHeight() {
return min_size;
}
#Override
protected int getSuggestedMinimumWidth() {
return min_size;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
rectF.set(strokeWidth / 2f, strokeWidth / 2f, width - strokeWidth / 2f, MeasureSpec.getSize(heightMeasureSpec) - strokeWidth / 2f);
float radius = width / 2f;
float angle = (360 - arcAngle) / 2f;
arcBottomHeight = radius * (float) (1 - Math.cos(angle / 180 * Math.PI));
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float startAngle = 90 - arcAngle / 2f; //270 for speed, 90 for fuel
float finishedSweepAngle = progress / (float) getMax() * arcAngle;
float finishedStartAngle = startAngle;
if(progress == 0) finishedStartAngle = 0.01f;
paint.setColor(unfinishedStrokeColor);
canvas.drawArc(rectF, startAngle, arcAngle, false, paint);
paint.setColor(finishedStrokeColor);
canvas.drawArc(rectF, finishedStartAngle, finishedSweepAngle, false, paint);
if(arcBottomHeight == 0) {
float radius = getWidth() / 2f;
float angle = (360 - arcAngle) / 2f;
arcBottomHeight = radius * (float) (1 - Math.cos(angle / 180 * Math.PI));
}
}
#Override
protected Parcelable onSaveInstanceState() {
final Bundle bundle = new Bundle();
bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
bundle.putFloat(INSTANCE_STROKE_WIDTH, getStrokeWidth());
bundle.putInt(instance_progress, getProgress());
bundle.putInt(INSTANCE_MAX, getMax());
bundle.putInt(INSTANCE_FINISHED_STROKE_COLOR, getFinishedStrokeColor());
bundle.putInt(INSTANCE_UNFINISHED_STROKE_COLOR, getUnfinishedStrokeColor());
bundle.putFloat(INSTANCE_ARC_ANGLE, getArcAngle());
return bundle;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
if(state instanceof Bundle) {
final Bundle bundle = (Bundle) state;
strokeWidth = bundle.getFloat(INSTANCE_STROKE_WIDTH);
setMax(bundle.getInt(INSTANCE_MAX));
setProgress(bundle.getInt(instance_progress));
finishedStrokeColor = bundle.getInt(INSTANCE_FINISHED_STROKE_COLOR);
unfinishedStrokeColor = bundle.getInt(INSTANCE_UNFINISHED_STROKE_COLOR);
initPainters();
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
return;
}
super.onRestoreInstanceState(state);
}
}
this is inside my MainLayout, this part I want to update:
<RelativeLayout
android:id="#+id/scale_gaz_inmain"
android:layout_width="#dimen/_57sdp"
android:layout_centerHorizontal="true"
android:layout_below="#+id/icon_gazinmain"
android:layout_height="#dimen/_60sdp"
>
<com.itelma.tele2.ArcProgressFuel
android:id="#+id/arc_progress2"
android:background="#android:color/transparent"
android:layout_width="match_parent"
android:scaleX="-1"
android:layout_height="match_parent"
custom:arc_progress="50"
custom:arc_unfinished_color="#color/mDark_gray"
custom:arc_finished_color="#color/colorApp"
custom:arc_max="100"/>
</RelativeLayout>
so in my main java file I have:
ArcProgressFuel mArcProgressFuel;
mArcProgressFuel=new ArcProgressFuel(this);
mArcProgressFuel.invalidate();
ok, I could resove it, with the following lines:
mArcProgressFuel=new ArcProgressFuel(this);
RelativeLayout relativeLayout2=(RelativeLayout)findViewById(R.id.speed_indicator);
View child = getLayoutInflater().inflate(R.layout.fragment_speed_indicator, null);
relativeLayout2.addView(child);
i have got some problem with my own progressbar.
When i click on dot they catch me.
I try do it something like that:
here is code:
package test.pionas.myapplication;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class PioArcCircle extends View {
private static final String TAG = PioArc.class.getSimpleName();
private static int INVALID_PROGRESS_VALUE = -1;
private float mThickness = 50f; // thickness of line
private int mRotate = 0; // rotate circle in degrees
private Paint mCircleBgPaint;
private int mCircleEndAngle = 270; // end arc
private int mCircleStartAngle = 0; // start arc
private int mCircleSweepAngle = 0; // actualy arc
private RectF mCircleOuterBounds;
private int mCircleBgColor = Color.RED; // color of circle
private Paint mCirclePaint; // progressbar
private int mCircleColor = Color.BLUE; // color of progressbar
private Paint mEraserPaint;
private RectF mCircleInnerBounds;
private int mEraserColor = Color.YELLOW; // background color of circle
private boolean mEraserInnerBackground = false; // eraser background inner circle
private Bitmap mBitmap;
private Canvas mCanvas;
private float mMinValue = 0; // min progressbar value
private float mMaxValue = 100; // max progressbar value
private float mProgressSweep = 0; // start progressbar value
private boolean mEnabled; // draw dot
private float mDotSize; // dot size
private Paint mCircleThumbPaint;
private float mTranslateX; // center circle (axis X)
private float mTranslateY; // center circle (axis Y)
private boolean mTouchInside; // touch inside circle can change position on progress
private float mTouchIgnoreRadius;
private int mArcRadius;
private int mThumbXPos;
private int mThumbYPos;
private OnPioArcCircleChangeListener mOnPioArcCircleChangeListener;
public PioArcCircle(Context context) {
super(context);
initDefaultValue(context, 0, null);
}
public PioArcCircle(Context context, AttributeSet attrs) {
super(context, attrs);
initDefaultValue(context, 0, attrs);
}
public PioArcCircle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initDefaultValue(context, defStyleAttr, attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public PioArcCircle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initDefaultValue(context, defStyleAttr, attrs);
}
private void initDefaultValue(Context context, int defStyleAttr, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.PioArcCircle,
defStyleAttr, 0);
this.mThickness = typedArray.getFloat(R.styleable.PioArcCircle_thickness1, this.mThickness);
this.mRotate = typedArray.getInt(R.styleable.PioArcCircle_rotate, this.mRotate);
this.mCircleSweepAngle = typedArray.getInt(R.styleable.PioArcCircle_circleSweepAngle, this.mCircleSweepAngle);
this.mCircleEndAngle = typedArray.getInt(R.styleable.PioArcCircle_circleEndAngle, this.mCircleEndAngle);
this.mCircleStartAngle = typedArray.getInt(R.styleable.PioArcCircle_circleStartAngle, this.mCircleStartAngle);
this.mCircleBgColor = typedArray.getInt(R.styleable.PioArcCircle_circleBgColor, this.mCircleBgColor);
this.mEraserColor = typedArray.getInt(R.styleable.PioArcCircle_eraserColor, this.mEraserColor);
this.mEraserInnerBackground = typedArray.getBoolean(R.styleable.PioArcCircle_eraserInnerBackground, this.mEraserInnerBackground);
this.mMinValue = typedArray.getFloat(R.styleable.PioArcCircle_minValue, this.mMinValue);
this.mMaxValue = typedArray.getFloat(R.styleable.PioArcCircle_maxValue, this.mMaxValue);
this.mEnabled = typedArray.getBoolean(R.styleable.PioArcCircle_enable, this.mEnabled);
this.mDotSize = typedArray.getFloat(R.styleable.PioArcCircle_dotSize, this.mDotSize);
this.mTouchInside = typedArray.getBoolean(R.styleable.PioArcCircle_touchInside, this.mTouchInside);
this.mCircleColor = typedArray.getInt(R.styleable.PioArcCircle_circleBgColor, this.mCircleColor);
}
mCircleBgPaint = new Paint();
mCircleBgPaint.setAntiAlias(true);
mCircleBgPaint.setColor(mCircleBgColor);
mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(mCircleColor);
mEraserPaint = new Paint();
mEraserPaint.setAntiAlias(true);
mEraserPaint.setColor(mEraserColor);
if (mEraserInnerBackground) {
mEraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
mCircleThumbPaint = new Paint();
mCircleThumbPaint.setAntiAlias(true);
mCircleThumbPaint.setColor(Color.CYAN);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mBitmap.eraseColor(Color.TRANSPARENT);
mCanvas = new Canvas(mBitmap);
}
super.onSizeChanged(w, h, oldw, oldh);
updateBounds();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
int min = Math.min(widthMeasureSpec, heightMeasureSpec);
this.setMeasuredDimension(parentWidth, parentHeight);
this.setTouchInSide(this.mTouchInside);
super.onMeasure(min, min);
}
#Override
protected void onDraw(Canvas canvas) {
mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
mCanvas.drawArc(mCircleOuterBounds, (mCircleStartAngle + mRotate), (mCircleEndAngle - mCircleStartAngle), true, mCircleBgPaint);
if (mCircleSweepAngle - mRotate > 0f) {
mCanvas.drawArc(mCircleOuterBounds, (mCircleStartAngle + mRotate), (mCircleSweepAngle - mRotate), true, mCirclePaint);
}
mCanvas.drawOval(mCircleInnerBounds, mEraserPaint);
if (mEnabled) {
mThumbXPos = (int) (mTranslateX + (mArcRadius * Math.cos(Math.toRadians((double) this.mCircleSweepAngle))));
mThumbYPos = (int) (mTranslateY + (mArcRadius * Math.sin(Math.toRadians((double) this.mCircleSweepAngle))));
mCanvas.drawCircle(mThumbXPos, mThumbYPos, mThickness, mCircleThumbPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, null);
}
private void updateBounds() {
if (this.getPaddingLeft() < (mThickness / 2)) {
this.setPadding((int) (mThickness / 2), this.getPaddingTop(), this.getPaddingRight(), this.getPaddingBottom());
}
mCircleOuterBounds = new RectF(0 + this.getPaddingLeft(), 0 + this.getPaddingLeft(), getWidth() - this.getPaddingLeft(), getHeight() - this.getPaddingLeft());
mCircleInnerBounds = new RectF(
mCircleOuterBounds.left + mThickness,
mCircleOuterBounds.top + mThickness,
mCircleOuterBounds.right - mThickness,
mCircleOuterBounds.bottom - mThickness);
this.mTranslateX = mCircleOuterBounds.centerX();
this.mTranslateY = mCircleOuterBounds.centerY();
this.mArcRadius = (int) (mTranslateX - this.getPaddingLeft() - (mThickness / 2));
invalidate();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (this.mEnabled) {
this.getParent().requestDisallowInterceptTouchEvent(true);
switch (event.getAction()) {
case 0:
this.onStartTrackingTouch();
this.updateOnTouch(event);
break;
case 1:
this.onStopTrackingTouch();
this.setPressed(false);
this.getParent().requestDisallowInterceptTouchEvent(false);
break;
case 2:
this.updateOnTouch(event);
break;
case 3:
this.onStopTrackingTouch();
this.setPressed(false);
this.getParent().requestDisallowInterceptTouchEvent(false);
}
return true;
} else {
return false;
}
}
public void setTouchInSide(boolean isEnabled) {
int thumbHalfheight = (int) (mThickness / 2);
int thumbHalfWidth = (int) (mThickness / 2);
this.mTouchInside = isEnabled;
if (this.mTouchInside) {
this.mTouchIgnoreRadius = (float) this.mArcRadius / 4.0F;
} else {
this.mTouchIgnoreRadius = (float) (this.mArcRadius - Math.min(thumbHalfWidth, thumbHalfheight));
}
}
private void updateOnTouch(MotionEvent event) {
boolean ignoreTouch = this.ignoreTouch(event.getX(), event.getY());
if (!ignoreTouch) {
this.setPressed(true);
this.mProgressSweep = (float) this.getTouchDegrees(event.getX(), event.getY());
this.updateProgress((int) this.mProgressSweep);
}
}
private double getTouchDegrees(float xPos, float yPos) {
double angle = (int) (Math.atan2(yPos - mTranslateY, xPos - mTranslateX) * 180 / Math.PI);
if (angle < 0) {
angle += 360;
}
float x = xPos - this.mTranslateX;
float y = yPos - this.mTranslateY;
angle = Math.toDegrees(Math.atan2((double) y, (double) x) + 1.5707963267948966D - Math.toRadians((double) this.mRotate));
if (angle < 0.0D) {
angle += 360.0D;
}
angle -= (double) this.mCircleStartAngle;
return angle;
}
private boolean ignoreTouch(float xPos, float yPos) {
boolean ignore = false;
double touchRadius = Math.sqrt(Math.pow(xPos - this.mTranslateX, 2) + Math.pow(yPos - this.mTranslateY, 2));
if (this.mTouchInside && touchRadius > this.mArcRadius) {
ignore = true;
} else {
if ((touchRadius > (this.mArcRadius + (this.mThickness / 2))) ||
(touchRadius < (this.mArcRadius - (this.mThickness / 2)))) {
ignore = true;
}
}
return ignore;
}
private void onStartTrackingTouch() {
if (this.mOnPioArcCircleChangeListener != null) {
this.mOnPioArcCircleChangeListener.onStartTrackingTouch(this);
}
}
private void onStopTrackingTouch() {
if (this.mOnPioArcCircleChangeListener != null) {
this.mOnPioArcCircleChangeListener.onStopTrackingTouch(this);
}
}
private void updateProgress(int progress) {
if (progress != INVALID_PROGRESS_VALUE) {
if (this.mOnPioArcCircleChangeListener != null) {
this.mOnPioArcCircleChangeListener.onProgressChanged(this);
}
mCircleSweepAngle = progress;
this.invalidate();
}
}
public OnPioArcCircleChangeListener getmOnPioArcCircleChangeListener() {
return mOnPioArcCircleChangeListener;
}
public void setmOnPioArcCircleChangeListener(OnPioArcCircleChangeListener mOnPioArcCircleChangeListener) {
this.mOnPioArcCircleChangeListener = mOnPioArcCircleChangeListener;
}
public interface OnPioArcCircleChangeListener {
void onProgressChanged(PioArcCircle var1);
void onStartTrackingTouch(PioArcCircle var1);
void onStopTrackingTouch(PioArcCircle var1);
}
}
activity_main.xml:
<com.test.myapplication.PioArcCircle
android:layout_width="200dp"
android:layout_height="200dp"
android:padding="#dimen/activity_vertical_margin"
android:progressDrawable="#drawable/circular_progress_bar"
pioarccircle:circleColor="#color/colorAccent"
pioarccircle:enable="true"
pioarccircle:minValue="50.0"
pioarccircle:rotate="135"
pioarccircle:thickness1="100" />
First problem:
How i can create a few colors of progress?
Thanks for help.
i have one fragment it contains one custom color seekbar and gridview . but when try to scroll seekbar its not moving . this fragment is of viewpager .
<com.example.app.ColorSeekBar
android:id="#+id/icon_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="6dp"
android:visibility="visible" />
<GridView
android:id="#+id/fragment_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/icon_color"
android:layout_marginTop="5dp"
android:background="#color/grid_bg_new"
android:drawSelectorOnTop="true"
android:focusableInTouchMode="true"
android:horizontalSpacing="5dp"
android:numColumns="3"
android:verticalSpacing="5dp"></GridView>
Please help me how can i accomplish viewpager move as well as seekbar move. when i move seekbar pager must not move and when i swipe page then seekbar must not move.
i also put
icons_pager.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
seekbar class
public ColorSeekBar(Context context) {
super(context);
init(context, null, 0, 0);
}
public ColorSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0, 0);
}
public ColorSeekBar(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ColorSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs, defStyleAttr, defStyleRes);
}
protected void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
applyStyle(context, attrs, defStyleAttr, defStyleRes);
}
public void applyStyle(int resId){
applyStyle(getContext(), null, 0, resId);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mViewWidth = widthMeasureSpec;
mViewHeight = heightMeasureSpec;
int speMode = MeasureSpec.getMode(heightMeasureSpec);
if(speMode == MeasureSpec.AT_MOST){
if(mIsShowAlphaBar){
setMeasuredDimension(mViewWidth,mThumbHeight * 2 + mBarHeight * 2 + mBarMargin);
}else{
setMeasuredDimension(mViewWidth,mThumbHeight + mBarHeight);
}
}
}
protected void applyStyle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes){
mContext = context;
//get attributes
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ColorSeekBar, defStyleAttr, defStyleRes);
int colorsId = a.getResourceId(R.styleable.ColorSeekBar_colors, 0);
mMaxValue = a.getInteger(R.styleable.ColorSeekBar_maxValue,100);
mColorBarValue = a.getInteger(R.styleable.ColorSeekBar_colorBarValue,0);
mAlphaBarValue = a.getInteger(R.styleable.ColorSeekBar_alphaBarValue,0);
mIsShowAlphaBar = a.getBoolean(R.styleable.ColorSeekBar_showAlphaBar, false);
mBackgroundColor = a.getColor(R.styleable.ColorSeekBar_bgColor, Color.TRANSPARENT);
mBarHeight = (int)a.getDimension(R.styleable.ColorSeekBar_barHeight,(float)dp2px(10));
mThumbHeight = (int)a.getDimension(R.styleable.ColorSeekBar_thumbHeight,(float)dp2px(30));
mBarMargin = (int)a.getDimension(R.styleable.ColorSeekBar_barMargin,(float)dp2px(5));
a.recycle();
if(colorsId != 0) mColors = getColorsById(colorsId);
setBackgroundColor(mBackgroundColor);
init();
//init color
pickColor(mColorBarValue);
setAlphaValue();
}
/**
*
* #param id
* #return
*/
private int[] getColorsById(int id){
if(isInEditMode()){
String[] s=mContext.getResources().getStringArray(id);
int[] colors = new int[s.length];
for (int j = 0; j < s.length; j++){
colors[j] = Color.parseColor(s[j]);
}
return colors;
}else{
TypedArray typedArray=mContext.getResources().obtainTypedArray(id);
int[] colors = new int[typedArray.length()];
for (int j = 0; j < typedArray.length(); j++){
colors[j] = typedArray.getColor(j,Color.BLACK);
}
typedArray.recycle();
return colors;
}
}
private void init() {
//init l r t b
realLeft = getPaddingLeft() + mPaddingSize;
realRight = getWidth() - getPaddingRight() - mPaddingSize;
realTop = getPaddingTop() + mPaddingSize;
realBottom = getHeight() - getPaddingBottom() - mPaddingSize;
//init size
mThumbRadius = mThumbHeight / 2;
mPaddingSize = (int)mThumbRadius;
mBarWidth = realRight - realLeft;
//init rect
mColorRect = new Rect(realLeft ,realTop,realRight,realTop + mBarHeight);
//init paint
mColorGradient = new LinearGradient(0, 0, mColorRect.width(), 0, mColors, null, Shader.TileMode.MIRROR);
mColorRectPaint = new Paint();
mColorRectPaint.setShader(mColorGradient);
mColorRectPaint.setAntiAlias(true);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mTransparentBitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_4444);
mTransparentBitmap.eraseColor(Color.TRANSPARENT);
}
public ColorSeekBar(Context context, float x1, float x2) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
init();
float colorPosition = (float) mColorBarValue / mMaxValue * mBarWidth;
Paint colorPaint = new Paint();
colorPaint.setAntiAlias(true);
colorPaint.setColor(pickColor(colorPosition));
int[] toAlpha=new int[]{Color.argb(255, mRed, mGreen, mBlue),Color.argb(0, mRed, mGreen, mBlue)};
//clear
canvas.drawBitmap(mTransparentBitmap,0,0,null);
//draw color bar
canvas.drawRect(mColorRect, mColorRectPaint);
//draw color bar thumb
float thumbX = colorPosition + realLeft;
float thumbY = mColorRect.top + mColorRect.height() / 2;
canvas.drawCircle(thumbX,thumbY , mBarHeight / 2 + 5, colorPaint);
//draw color bar thumb radial gradient shader
RadialGradient thumbShader = new RadialGradient(thumbX, thumbY, mThumbRadius, toAlpha, null, Shader.TileMode.MIRROR);
Paint thumbGradientPaint = new Paint();
thumbGradientPaint.setAntiAlias(true);
thumbGradientPaint.setShader(thumbShader);
canvas.drawCircle(thumbX, thumbY, mThumbHeight / 2, thumbGradientPaint);
if(mIsShowAlphaBar){
//init rect
int top = (int)(mThumbHeight+ mThumbRadius + mBarHeight + mBarMargin);
mAlphaRect = new Rect(realLeft,top,realRight,top + mBarHeight);
//draw alpha bar
Paint alphaBarPaint = new Paint();
alphaBarPaint.setAntiAlias(true);
LinearGradient alphaBarShader = new LinearGradient(0, 0, mAlphaRect.width(), 0, toAlpha, null, Shader.TileMode.MIRROR);
alphaBarPaint.setShader(alphaBarShader);
canvas.drawRect(mAlphaRect,alphaBarPaint);
//draw alpha bar thumb
float alphaPosition = (float) mAlphaBarValue / 255 * mBarWidth;
float alphaThumbX = alphaPosition + realLeft;
float alphaThumbY = mAlphaRect.top + mAlphaRect.height() / 2;
canvas.drawCircle(alphaThumbX, alphaThumbY, mBarHeight / 2 + 5, colorPaint);
//draw alpha bar thumb radial gradient shader
RadialGradient alphaThumbShader = new RadialGradient(alphaThumbX, alphaThumbY, mThumbRadius, toAlpha, null, Shader.TileMode.MIRROR);
Paint alphaThumbGradientPaint = new Paint();
alphaThumbGradientPaint.setAntiAlias(true);
alphaThumbGradientPaint.setShader(alphaThumbShader);
canvas.drawCircle(alphaThumbX,alphaThumbY, mThumbHeight/2, alphaThumbGradientPaint);
}
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
if(isOnBar(mColorRect, x, y)){
mMovingColorBar = true;
}else if(mIsShowAlphaBar){
if(isOnBar(mAlphaRect, x, y)){
mMovingAlphaBar = true;
}
}
break;
case MotionEvent.ACTION_MOVE:
if(mMovingColorBar){
float value = (x - realLeft) / mBarWidth * mMaxValue;
mColorBarValue =(int)value ;
if (mColorBarValue < 0) mColorBarValue = 0;
if (mColorBarValue > mMaxValue) mColorBarValue = mMaxValue;
}else if(mIsShowAlphaBar){
if(mMovingAlphaBar){
float value = (x - realLeft) / mBarWidth * 255;
mAlphaBarValue = (int)value;
if (mAlphaBarValue < 0 ) mAlphaBarValue = 0;
if (mAlphaBarValue > 255 ) mAlphaBarValue = 255;
setAlphaValue();
}
}
if(mOnColorChangeLister != null && (mMovingAlphaBar || mMovingColorBar))
mOnColorChangeLister.onColorChangeListener(mColorBarValue, mAlphaBarValue,getColor());
invalidate();
break;
case MotionEvent.ACTION_UP:
mMovingColorBar = false;
mMovingAlphaBar = false;
break;
}
return true;
}
/**
*
* #param r
* #param x
* #param y
* #return whether MotionEvent is performing on bar or not
*/
private boolean isOnBar(Rect r, float x, float y){
if(r.left - mThumbRadius < x && x < r.right + mThumbRadius && r.top - mThumbRadius < y && y < r.bottom + mThumbRadius){
return true;
}else{
return false;
}
}
/**
*
* #param position
* #return color
*/
private int pickColor(float position) {
float unit = position / mBarWidth;
if (unit <= 0.0)
return mColors[0];
if (unit >= 1)
return mColors[mColors.length - 1];
float colorPosition = unit * (mColors.length - 1);
int i = (int)colorPosition;
colorPosition -= i;
c0 = mColors[i];
c1 = mColors[i+1];
// mAlpha = mix(Color.alpha(c0), Color.alpha(c1), colorPosition);
mRed = mix(Color.red(c0), Color.red(c1), colorPosition);
mGreen = mix(Color.green(c0), Color.green(c1), colorPosition);
mBlue = mix(Color.blue(c0), Color.blue(c1), colorPosition);
return Color.rgb( mRed, mGreen, mBlue);
}
/**
*
* #param start
* #param end
* #param position
* #return
*/
private int mix(int start, int end, float position) {
return start + Math.round(position * (end - start));
}
public int getColor() {
if(mIsShowAlphaBar) return Color.argb(mAlpha, mRed, mGreen, mBlue);
return Color.rgb( mRed, mGreen, mBlue);
}
public int getAlphaValue(){
return mAlpha;
}
/**
* #return color with alpha value
*/
public int getColorWithAlpha(){
return Color.argb(mAlpha, mRed, mGreen, mBlue);
}
public interface OnColorChangeListener {
/**
* #param colorBarValue between 0-maxValue
* #param alphaValue between 0-255
* #param color return the color contains alpha value whether showAlphaBar is true or without alpha value
*/
public void onColorChangeListener(int colorBarValue, int alphaValue, int color);
}
/**
* #param onColorChangeListener
*/
public void setOnColorChangeListener(OnColorChangeListener onColorChangeListener){
this.mOnColorChangeLister = onColorChangeListener;
}
public int dp2px(float dpValue) {
final float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* Set colors by resource id. The resource's type must be color
* #param resId
*/
public void setColors(int resId){
setColors(getColorsById(resId));
}
public void setColors(int[] colors){
mColors = colors;
invalidate();
setAlphaValue();
if(mOnColorChangeLister != null)
mOnColorChangeLister.onColorChangeListener(mColorBarValue, mAlphaBarValue,getColor());
}
public int[] getColors(){
return mColors;
}
public boolean isShowAlphaBar(){
return mIsShowAlphaBar;
}
private void refreshLayoutParams(){
mThumbHeight = mThumbHeight < 2? 2:mThumbHeight;
mBarHeight = mBarHeight < 2? 2:mBarHeight;
int singleHeight = mThumbHeight + mBarHeight;
int doubleHeight = mThumbHeight *2 + mBarHeight * 2 + mBarMargin;
if(getLayoutParams().height == -2) {
if(mIsShowAlphaBar){
getLayoutParams().height = doubleHeight;
setLayoutParams(getLayoutParams());
}else{
getLayoutParams().height = singleHeight ;
setLayoutParams(getLayoutParams());
}
}else if (getLayoutParams().height >= 0){
if(mIsShowAlphaBar){
getLayoutParams().height = doubleHeight;
setLayoutParams(getLayoutParams());
}else{
getLayoutParams().height = singleHeight;
setLayoutParams(getLayoutParams());
}
}
}
public void setShowAlphaBar(boolean show){
mIsShowAlphaBar = show;
refreshLayoutParams();
invalidate();
if(mOnColorChangeLister != null)
mOnColorChangeLister.onColorChangeListener(mColorBarValue, mAlphaBarValue,getColor());
}
/**
* #param dp
*/
public void setBarHeight(float dp){
mBarHeight = dp2px(dp);
refreshLayoutParams();
invalidate();
}
/**
* #param px
*/
public void setBarHeightPx(int px){
mBarHeight = px;
refreshLayoutParams();
invalidate();
}
private void setAlphaValue(){
mAlpha = 255 - mAlphaBarValue;
}
public void setAlphaBarValue(int value) {
this.mAlphaBarValue = value;
setAlphaValue();
invalidate();
}
public int getMaxValue() {
return mMaxValue;
}
public void setMaxValue(int value) {
this.mMaxValue = value;
invalidate();
}
/**
* set margin between bars
* #param mBarMargin
*/
public void setBarMargin(float mBarMargin) {
this.mBarMargin = dp2px(mBarMargin);
refreshLayoutParams();
invalidate();
}
/**
* set margin between bars
* #param mBarMargin
*/
public void setBarMarginPx(int mBarMargin) {
this.mBarMargin = mBarMargin;
refreshLayoutParams();
invalidate();
}
/**
* Set the value of color bar, if out of bounds , it will be 0 or maxValue;
* #param value
*/
public void setColorBarValue(int value) {
this.mColorBarValue = value;
invalidate();
if(mOnColorChangeLister != null)
mOnColorChangeLister.onColorChangeListener(mColorBarValue, mAlphaBarValue,getColor());
}
/**
* set thumb's height by dpi
* #param dp
*/
public void setThumbHeight(float dp) {
this.mThumbHeight = dp2px(dp);
refreshLayoutParams();
invalidate();
}
/**
* set thumb's height by pixels
* #param px
*/
public void setThumbHeightPx(int px) {
this.mThumbHeight = px;
refreshLayoutParams();
invalidate();
}
public int getBarHeight() {
return mBarHeight;
}
public int getThumbHeight() {
return mThumbHeight;
}
public int getBarMargin() {
return mBarMargin;
}
public float getColorPosition() {
return mColorBarValue;
}
}
I am using a custom layout to display a varied number of buttons and intercept their clicks. Here is the source code for the custom layout:
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.AdapterView;
public class FlowLayout extends AdapterView<Adapter> {
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
private static final int INVALID_INDEX = -1;
private static final int TOUCH_STATE_RESTING = 0;
private static final int TOUCH_STATE_CLICK = 1;
private int mTouchState = TOUCH_STATE_RESTING;
private Rect mRect;
private Runnable mLongPressRunnable;
private int mTouchStartX;
private int mTouchStartY;
private int horizontalSpacing = 0;
private int verticalSpacing = 0;
private int orientation = 0;
private boolean debugDraw = false;
private Adapter mAdapter;
private final AdapterObserver mObserver = new AdapterObserver();
public FlowLayout(Context context) {
super(context);
this.readStyleParameters(context, null);
}
public FlowLayout(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
this.readStyleParameters(context, attributeSet);
}
public FlowLayout(Context context, AttributeSet attributeSet, int defStyle) {
super(context, attributeSet, defStyle);
this.readStyleParameters(context, attributeSet);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
int size;
int mode;
if (orientation == HORIZONTAL) {
size = sizeWidth;
mode = modeWidth;
} else {
size = sizeHeight;
mode = modeHeight;
}
int lineThicknessWithSpacing = 0;
int lineThickness = 0;
int lineLengthWithSpacing = 0;
int lineLength;
int prevLinePosition = 0;
int controlMaxLength = 0;
int controlMaxThickness = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
child.measure(
MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeWidth),
MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeHeight)
);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int hSpacing = this.getHorizontalSpacing(lp);
int vSpacing = this.getVerticalSpacing(lp);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childLength;
int childThickness;
int spacingLength;
int spacingThickness;
if (orientation == HORIZONTAL) {
childLength = childWidth;
childThickness = childHeight;
spacingLength = hSpacing;
spacingThickness = vSpacing;
} else {
childLength = childHeight;
childThickness = childWidth;
spacingLength = vSpacing;
spacingThickness = hSpacing;
}
lineLength = lineLengthWithSpacing + childLength;
lineLengthWithSpacing = lineLength + spacingLength;
boolean newLine = lp.newLine || (mode != MeasureSpec.UNSPECIFIED && lineLength > size);
if (newLine) {
prevLinePosition = prevLinePosition + lineThicknessWithSpacing;
lineThickness = childThickness;
lineLength = childLength;
lineThicknessWithSpacing = childThickness + spacingThickness;
lineLengthWithSpacing = lineLength + spacingLength;
}
lineThicknessWithSpacing = Math.max(lineThicknessWithSpacing, childThickness + spacingThickness);
lineThickness = Math.max(lineThickness, childThickness);
int posX;
int posY;
if (orientation == HORIZONTAL) {
posX = getPaddingLeft() + lineLength - childLength;
posY = getPaddingTop() + prevLinePosition;
} else {
posX = getPaddingLeft() + prevLinePosition;
posY = getPaddingTop() + lineLength - childHeight;
}
lp.setPosition(posX, posY);
controlMaxLength = Math.max(controlMaxLength, lineLength);
controlMaxThickness = prevLinePosition + lineThickness;
}
if (orientation == HORIZONTAL) {
this.setMeasuredDimension(resolveSize(controlMaxLength, widthMeasureSpec), resolveSize(controlMaxThickness, heightMeasureSpec));
} else {
this.setMeasuredDimension(resolveSize(controlMaxThickness, widthMeasureSpec), resolveSize(controlMaxLength, heightMeasureSpec));
}
}
private int getVerticalSpacing(LayoutParams lp) {
int vSpacing;
if (lp.verticalSpacingSpecified()) {
vSpacing = lp.verticalSpacing;
} else {
vSpacing = this.verticalSpacing;
}
return vSpacing;
}
private int getHorizontalSpacing(LayoutParams lp) {
int hSpacing;
if (lp.horizontalSpacingSpecified()) {
hSpacing = lp.horizontalSpacing;
} else {
hSpacing = this.horizontalSpacing;
}
return hSpacing;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
}
}
#Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean more = super.drawChild(canvas, child, drawingTime);
this.drawDebugInfo(canvas, child);
return more;
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
#Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attributeSet) {
return new LayoutParams(getContext(), attributeSet);
}
#Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
private void readStyleParameters(Context context, AttributeSet attributeSet) {
TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout);
try {
horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0);
verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0);
orientation = a.getInteger(R.styleable.FlowLayout_orientation, HORIZONTAL);
debugDraw = a.getBoolean(R.styleable.FlowLayout_debugDraw, false);
} finally {
a.recycle();
}
}
private void drawDebugInfo(Canvas canvas, View child) {
if (!debugDraw) {
return;
}
Paint childPaint = this.createPaint(0xffffff00);
Paint layoutPaint = this.createPaint(0xff00ff00);
Paint newLinePaint = this.createPaint(0xffff0000);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.horizontalSpacing > 0) {
float x = child.getRight();
float y = child.getTop() + child.getHeight() / 2.0f;
canvas.drawLine(x, y, x + lp.horizontalSpacing, y, childPaint);
canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y - 4.0f, x + lp.horizontalSpacing, y, childPaint);
canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y + 4.0f, x + lp.horizontalSpacing, y, childPaint);
} else if (this.horizontalSpacing > 0) {
float x = child.getRight();
float y = child.getTop() + child.getHeight() / 2.0f;
canvas.drawLine(x, y, x + this.horizontalSpacing, y, layoutPaint);
canvas.drawLine(x + this.horizontalSpacing - 4.0f, y - 4.0f, x + this.horizontalSpacing, y, layoutPaint);
canvas.drawLine(x + this.horizontalSpacing - 4.0f, y + 4.0f, x + this.horizontalSpacing, y, layoutPaint);
}
if (lp.verticalSpacing > 0) {
float x = child.getLeft() + child.getWidth() / 2.0f;
float y = child.getBottom();
canvas.drawLine(x, y, x, y + lp.verticalSpacing, childPaint);
canvas.drawLine(x - 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint);
canvas.drawLine(x + 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint);
} else if (this.verticalSpacing > 0) {
float x = child.getLeft() + child.getWidth() / 2.0f;
float y = child.getBottom();
canvas.drawLine(x, y, x, y + this.verticalSpacing, layoutPaint);
canvas.drawLine(x - 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint);
canvas.drawLine(x + 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint);
}
if (lp.newLine) {
if (orientation == HORIZONTAL) {
float x = child.getLeft();
float y = child.getTop() + child.getHeight() / 2.0f;
canvas.drawLine(x, y - 6.0f, x, y + 6.0f, newLinePaint);
} else {
float x = child.getLeft() + child.getWidth() / 2.0f;
float y = child.getTop();
canvas.drawLine(x - 6.0f, y, x + 6.0f, y, newLinePaint);
}
}
}
private Paint createPaint(int color) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(color);
paint.setStrokeWidth(2.0f);
return paint;
}
public static class LayoutParams extends ViewGroup.LayoutParams {
private static int NO_SPACING = -1;
private int x;
private int y;
private int horizontalSpacing = NO_SPACING;
private int verticalSpacing = NO_SPACING;
private boolean newLine = false;
public LayoutParams(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
this.readStyleParameters(context, attributeSet);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams layoutParams) {
super(layoutParams);
}
public boolean horizontalSpacingSpecified() {
return horizontalSpacing != NO_SPACING;
}
public boolean verticalSpacingSpecified() {
return verticalSpacing != NO_SPACING;
}
public void setHorizontalSpacing(int hs) {
horizontalSpacing = hs;
}
public void setVerticalSpacing(int vs) {
verticalSpacing = vs;
}
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
private void readStyleParameters(Context context, AttributeSet attributeSet) {
TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams);
try {
horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, NO_SPACING);
verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_verticalSpacing, NO_SPACING);
newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false);
} finally {
a.recycle();
}
}
}
#Override
public Adapter getAdapter() {
return mAdapter;
}
#Override
public View getSelectedView() {
throw new UnsupportedOperationException("Not supported");
}
#Override
public void setAdapter(Adapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
mAdapter = adapter;
mAdapter.registerDataSetObserver(mObserver);
refresh();
}
public void refresh() {
removeAllViewsInLayout();
for (int i = 0; i < mAdapter.getCount(); i++) {
final View view = mAdapter.getView(i, null, this);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params == null) {
params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
addViewInLayout(view, i, params, true);
}
postInvalidate();
requestLayout();
}
public class AdapterObserver extends DataSetObserver {
#Override
public void onChanged() {
refresh();
}
#Override
public void onInvalidated() {
}
}
#Override
public void setSelection(int position) {
throw new UnsupportedOperationException("Not supported");
}
// Touch detection
#Override
public boolean onTouchEvent(MotionEvent event) {
if (getChildCount() == 0) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTouch(event);
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_CLICK) {
clickChildAt((int)event.getX(), (int)event.getY());
}
endTouch();
break;
default:
endTouch();
break;
}
return true;
}
/**
* Sets and initializes all things that need to when we start a touch
* gesture.
*
* #param event The down event
*/
private void startTouch(final MotionEvent event) {
mTouchStartX = (int)event.getX();
mTouchStartY = (int)event.getY();
startLongPressCheck();
mTouchState = TOUCH_STATE_CLICK;
}
private void startLongPressCheck() {
if (mLongPressRunnable == null) {
mLongPressRunnable = new Runnable() {
public void run() {
if (mTouchState == TOUCH_STATE_CLICK) {
final int index = getContainingChildIndex(mTouchStartX, mTouchStartY);
if (index != INVALID_INDEX) { longClickChild(index); mTouchState = TOUCH_STATE_RESTING; }
}
}
};
}
postDelayed(mLongPressRunnable, 300); //ViewConfiguration.getLongPressTimeout()
}
private void longClickChild(final int index) {
final View itemView = getChildAt(index);
final int position = index;
final long id = mAdapter.getItemId(position);
final OnItemLongClickListener listener = getOnItemLongClickListener();
if (listener != null) { listener.onItemLongClick(this, itemView, position, id); }
}
private int getContainingChildIndex(final int x, final int y) {
if (mRect == null) { mRect = new Rect(); }
for (int index = 0; index < getChildCount(); index++) {
getChildAt(index).getHitRect(mRect);
if (mRect.contains(x, y)) { return index; }
}
return INVALID_INDEX;
}
private void endTouch() {
removeCallbacks(mLongPressRunnable);
mTouchState = TOUCH_STATE_RESTING;
}
private void clickChildAt(final int x, final int y) {
final int index = getContainingChildIndex(x, y);
if (index != INVALID_INDEX) {
final View itemView = getChildAt(index);
final int position = index;
final long id = mAdapter.getItemId(position);
performItemClick(itemView, position, id);
}
}
}
This code works on my test device which is a Google Nexus S with Android 4.1.2, meaning that the buttons are clickable. Yet I got reports that the buttons are unresponsive on other devices such as Android Casio C771 with Android version 2.3.3 and Verizon LG VS840 with Android 4.0.4.
Can you please tell me what could cause this discrepancy and how can I fix it?
Thank you
Things to look out for:
It is essential that the Views created for the adapter are enabled for click and touch action. After they are created:
View.setEnabled(true);
When you create the AdapterView and the BaseApapter, remember to both setOnItemClickListener and setOnItemLongClickListener if you want to handle long clicks, which it seems you do.
In the endTouch routine, you need to set mLongPressRunnable to null, so it will be created for the next touch (or lose the null check in startLongPressCheck and handle concurency issues another way).
The runnable created in startLongPressCheck needs to call endTouch when complete to reset everything to the right, nothing pending, state after the long press time period.
In the onTouchEvent switch statement, it is important to not call your endTouch routine, because this means that movement events may stop the click.
There is a suggestion (see Android onClick method doesn't work on a custom view) that if you don't call super.onTouchEvent(event) in your onTouchEvent it can cause problems. This would look something like:
#Override
public boolean onTouchEvent(MotionEvent event) {
if (getChildCount() == 0) {
return super.onTouchEvent(event);
}
boolean handled = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTouch(event);
handled = true;
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_CLICK) {
clickChildAt((int)event.getX(), (int)event.getY());
handled = true;
}
endTouch();
break;
default:
// Do not do anything dramatic here because the system
// may send different (eg. motion) information here which
// may lead to you losing valid clicks if you simply cancel
// the click in process.
break;
}
if (handled == false) handled = super.onTouchEvent(event);
return handled;
}