Set a gravity and padding to the view - android

I was looking for how implement a color picker and I found this
wonderful answers of #Raghunandan that nicely works.
The only problem is:
I can't centralize the view on dialog, it always been on top|left on dialog. I can't even set a padding. Anyone knows how I can fix this?
And if possible how can I change the dialog theme to Holo (Black), my entire app use this theme.
[EDITED]
The code is:
public class ColorPickerDialog extends Dialog {
public interface OnColorChangedListener {
void colorChanged(int color);
}
private OnColorChangedListener mListener;
private int mInitialColor;
private static class ColorPickerView extends View {
private Paint mPaint;
private Paint mCenterPaint;
private final int[] mColors;
private OnColorChangedListener mListener;
ColorPickerView(Context c, OnColorChangedListener l, int color) {
super(c);
mListener = l;
mColors = new int[] {
0xFFFF0000, 0xFFFF00FF, 0xFF0000FF, 0xFF00FFFF, 0xFF00FF00,
0xFFFFFF00, 0xFFFF0000
};
Shader s = new SweepGradient(0, 0, mColors, null);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(s);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(32);
mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCenterPaint.setColor(color);
mCenterPaint.setStrokeWidth(5);
}
private boolean mTrackingCenter;
private boolean mHighlightCenter;
#Override
protected void onDraw(Canvas canvas) {
float r = CENTER_X - mPaint.getStrokeWidth()*0.5f;
canvas.translate(CENTER_X, CENTER_X);
canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);
if (mTrackingCenter) {
int c = mCenterPaint.getColor();
mCenterPaint.setStyle(Paint.Style.STROKE);
if (mHighlightCenter) {
mCenterPaint.setAlpha(0xFF);
} else {
mCenterPaint.setAlpha(0x80);
}
canvas.drawCircle(0, 0,
CENTER_RADIUS + mCenterPaint.getStrokeWidth(),
mCenterPaint);
mCenterPaint.setStyle(Paint.Style.FILL);
mCenterPaint.setColor(c);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(CENTER_X*2, CENTER_Y*2);
}
private static final int CENTER_X = 100;
private static final int CENTER_Y = 100;
private static final int CENTER_RADIUS = 32;
private int floatToByte(float x) {
int n = java.lang.Math.round(x);
return n;
}
private int pinToByte(int n) {
if (n < 0) {
n = 0;
} else if (n > 255) {
n = 255;
}
return n;
}
private int ave(int s, int d, float p) {
return s + java.lang.Math.round(p * (d - s));
}
private int interpColor(int colors[], float unit) {
if (unit <= 0) {
return colors[0];
}
if (unit >= 1) {
return colors[colors.length - 1];
}
float p = unit * (colors.length - 1);
int i = (int)p;
p -= i;
// now p is just the fractional part [0...1) and i is the index
int c0 = colors[i];
int c1 = colors[i+1];
int a = ave(Color.alpha(c0), Color.alpha(c1), p);
int r = ave(Color.red(c0), Color.red(c1), p);
int g = ave(Color.green(c0), Color.green(c1), p);
int b = ave(Color.blue(c0), Color.blue(c1), p);
return Color.argb(a, r, g, b);
}
private int rotateColor(int color, float rad) {
float deg = rad * 180 / 3.1415927f;
int r = Color.red(color);
int g = Color.green(color);
int b = Color.blue(color);
ColorMatrix cm = new ColorMatrix();
ColorMatrix tmp = new ColorMatrix();
cm.setRGB2YUV();
tmp.setRotate(0, deg);
cm.postConcat(tmp);
tmp.setYUV2RGB();
cm.postConcat(tmp);
final float[] a = cm.getArray();
int ir = floatToByte(a[0] * r + a[1] * g + a[2] * b);
int ig = floatToByte(a[5] * r + a[6] * g + a[7] * b);
int ib = floatToByte(a[10] * r + a[11] * g + a[12] * b);
return Color.argb(Color.alpha(color), pinToByte(ir),
pinToByte(ig), pinToByte(ib));
}
private static final float PI = 3.1415926f;
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX() - CENTER_X;
float y = event.getY() - CENTER_Y;
boolean inCenter = java.lang.Math.sqrt(x*x + y*y) <= CENTER_RADIUS;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTrackingCenter = inCenter;
if (inCenter) {
mHighlightCenter = true;
invalidate();
break;
}
case MotionEvent.ACTION_MOVE:
if (mTrackingCenter) {
if (mHighlightCenter != inCenter) {
mHighlightCenter = inCenter;
invalidate();
}
} else {
float angle = (float)java.lang.Math.atan2(y, x);
// need to turn angle [-PI ... PI] into unit [0....1]
float unit = angle/(2*PI);
if (unit < 0) {
unit += 1;
}
mCenterPaint.setColor(interpColor(mColors, unit));
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (mTrackingCenter) {
if (inCenter) {
mListener.colorChanged(mCenterPaint.getColor());
}
mTrackingCenter = false; // so we draw w/o halo
invalidate();
}
break;
}
return true;
}
}
public ColorPickerDialog(Context context,
OnColorChangedListener listener,
int initialColor) {
super(context);
mListener = listener;
mInitialColor = initialColor;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnColorChangedListener l = new OnColorChangedListener() {
public void colorChanged(int color) {
mListener.colorChanged(color);
dismiss();
}
};
setContentView(new ColorPickerView(getContext(), l, mInitialColor));
setTitle("Pick a Color");
}
}
and to exib the dialog:
button.setOnClickListener(new OnClickListener(){
public void OnClick(View v){
//param - context / listener / inicialColor
new ColorPickerDialog(MainActivity.this, this, Color.RED).show();
}
});

OPTION 1:
In your custom view you can override onSizeChanged like this:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
width = w;
height = h;
// Move your calculation logic here.
super.onSizeChanged(w, h, oldw, oldh);
}
This way you know the size of your view when it's set as the content of the dialog. Knowing this in your onDraw() method you can easily calculate the center of the view by using width / 2 and height / 2. Your draw calls can be modified to draw in the center:
int centerX = widht / 2;
int centerY = height / 2;
int offset = *Your required view size here* / 2;
canvas.drawOval(new RectF(centerX - offset, 0, centerX + offset, height), mPaint);
canvas.drawCircle(centerX, centerY, CENTER_RADIUS, mCenterPaint);
This way the view will draw centered horizontally and will fill all the height. If you need you can also center it vertically the same way as with the left and right coordinates of the rect. Also it's a good practice to avoid allocating objects in the onDraw() method because depending on the view it may be called a lot of times (during animations etc.). You can calculate your RectF as soon as you know the size of the view and that is in onSizeChanged().
OPTION 2:
You can probably avoid modifying your custom view by just setting correct layout parameters when adding it to the dialog. Dialog uses ViewGroup.LayoutParams if i remember correctly. They don't have a gravity field. So In your dialogs onCreate you can just wrap your view in a LinearLayout or any other that supports gravity and set center gravity to your view:
LinearLayout layout = new LinearLayout(getContext());
YourView view = new ColorPickerView(getContext(), l, mInitialColor);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(*Width of you view or wrap_content*,*height of your view or wrap_content*);
params.gravity = Gravity.CENTER_HORIZONTAL;
view.setLayoutParams(params);
layout.addView(view)
setContentView(layout);

Related

How to make Progress bar like Linkedin to show profile status?

I wanted to show profile status using a Progress bar just like Linkedin, I searched everywhere but didn't get any reference related to that.
My code:
public class ProgressDrawable extends Drawable {
private static final int NUM_SEGMENTS = 5;
private final int mForeground;
private final int mBackground;
private final Paint mPaint = new Paint();
private final RectF mSegment = new RectF();
public ProgressDrawable(int fgColor, int bgColor) {
mForeground = fgColor;
mBackground = bgColor;
}
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void draw(Canvas canvas) {
float level = getLevel() / 10000f;
Rect b = getBounds();
float gapWidth = b.height() / 10f;
float segmentWidth = (b.width() - (NUM_SEGMENTS - 1) * gapWidth) / NUM_SEGMENTS;
mSegment.set(0, 0, segmentWidth, b.height());
mPaint.setColor(mForeground);
for (int i = 0; i < NUM_SEGMENTS; i++) {
float loLevel = i / (float) NUM_SEGMENTS;
float hiLevel = (i + 1) / (float) NUM_SEGMENTS;
if (loLevel <= level && level <= hiLevel) {
float middle = mSegment.left + NUM_SEGMENTS * segmentWidth * (level - loLevel);
canvas.drawRect(mSegment.left, mSegment.top, middle, mSegment.bottom, mPaint);
mPaint.setColor(mBackground);
canvas.drawRect(middle, mSegment.top, mSegment.right, mSegment.bottom, mPaint);
} else {
canvas.drawRect(mSegment, mPaint);
}
mSegment.offset(mSegment.width() + gapWidth, 0);
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
In this code, all the blocks have same color, but as per requirement, all block colors should be different.

Android - rotate and fill animation

I'm trying to figure out how to fill an View clockwise.
I figured out how to rotate an image but not sure how to rotate and fill.
Used this class to create a circle:
public class Circle extends View {
private static final int START_ANGLE_POINT = 270;
private final Paint paint;
private RectF rect;
private float angle;
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 60;
Point[] points = new Point[3];
points[0] = new Point(7, 13);
points[1] = new Point(13, 19);
points[2] = new Point(21, 9);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
//Circle color
paint.setColor(Theme.darkRedColour());
//Initial Angle (optional, it can be zero)
angle = 0;
}
#Override
protected void onDraw(Canvas canvas) {
if (rect == null) {
DisplayMetrics metrics = App.getAppContext().getResources().getDisplayMetrics();
int densityDpi = (int)metrics.density;
densityDpi = 3;
int canvasW = getWidth();
int canvasH = getHeight();
Point centerOfCanvas = new Point(canvasW / 2, canvasH / 2);
int rectW = 100; // * (densityDpi - 1);
int rectH = 100; // * (densityDpi - 1);
int left = centerOfCanvas.x - (rectW / 2);
int top = centerOfCanvas.y - (rectH / 2);
int right = centerOfCanvas.x + (rectW / 2);
int bottom = centerOfCanvas.y + (rectH / 2);
rect = new RectF(left, top, right, bottom);
}
super.onDraw(canvas);
canvas.drawArc(rect, START_ANGLE_POINT, angle, true, paint);
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
}
}
Then used an AnimiationListener and updated the angle.

Custom drawable with ImageView

I have already an 'ImageView' with these parameters:
android:layout_width="wrap_content"
android:layout_height="wrap_content"
and set custom Drawable :
public class HexDrawable extends Drawable {
private Path hexagonPath;
private float mWidth, mHeight;
private int mBackgroundColor;
private int mStrokeColor;
private int mStrokeWidth;
public HexDrawable(){
init();
}
public void setBackgroundColor(int color) {
mBackgroundColor = color;
}
public void setStrokeWidth(int width) {
mStrokeWidth = width;
}
public void setStrokeColor(int color) {
mStrokeColor = color;
}
#Override
public int getIntrinsicHeight() {
return 60;
}
#Override
public int getIntrinsicWidth() {
return 60;
}
private void init() {
hexagonPath = new Path();
mBackgroundColor = Color.BLUE;
mStrokeColor = Color.GREEN;
mStrokeWidth = 4;
}
private void calculatePath() {
float p = mStrokeWidth / 2;
float w = mWidth - 2 * p;
float h = mHeight - 2 * p;
float r = h / 2;
float a = (float) (r / Math.sqrt(3));
PointF X = new PointF(p + a + r / 2, p);
PointF Y = new PointF(p + a + r , p);
PointF A = new PointF(p + a, p + 0f);
PointF B = new PointF(p + 0f, p + r);
PointF C = new PointF(p + a, p + 2 * r);
PointF D = new PointF(p + w - a, p + 2 * r);
PointF E = new PointF(p + w, p + r);
PointF F = new PointF(p + w - a, p + 0);
hexagonPath.moveTo(Y.x, Y.y);
hexagonPath.lineTo(A.x, A.y);
hexagonPath.lineTo(B.x, B.y);
hexagonPath.lineTo(C.x, C.y);
hexagonPath.lineTo(D.x, D.y);
hexagonPath.lineTo(E.x, E.y);
hexagonPath.lineTo(F.x, F.y);
hexagonPath.lineTo(X.x, X.y);
}
#Override
protected void onBoundsChange(Rect bounds) {
mWidth = bounds.width();
mHeight = bounds.height();
calculatePath();
}
#Override
public void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(mStrokeColor); // set the color
paint.setStrokeWidth(mStrokeWidth); // set the size
paint.setDither(true); // set the dither to true
paint.setStyle(Paint.Style.STROKE); // set to STOKE
paint.setStrokeJoin(Paint.Join.ROUND); // set the join to round you want
paint.setStrokeCap(Paint.Cap.ROUND); // set the paint cap to round too
paint.setPathEffect(new CornerPathEffect(mStrokeWidth)); // set the path effect when they join.
paint.setAntiAlias(true);
canvas.drawPath(hexagonPath, paint);
canvas.clipPath(hexagonPath, Region.Op.INTERSECT);
canvas.drawColor(mBackgroundColor);
canvas.drawPath(hexagonPath, paint);
canvas.save();
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter colorFilter) {
}
#Override
public int getOpacity() {
return 0;
}
}
It seems that ImageView use all width in this case.
How to implements Drawable correctly to use it with ImageView?
The root of the problem was clip mode.
Its better to use canvas.clipPath(hexagonPath, Region.Op.REPLACE);
Also, question example works well with ImageView, but after deep investigation I undestand, that at android 5.0 and above this drawable is used at drawableLeft in TextView.
Also its not need to override getIntrinsicHeight
Your code is absolutely correct:
This is how I fill ImageView (in onCreate() of activity):
((ImageView)findViewById(R.id.hexImageView)).setImageDrawable(new HexDrawable());
Layout of the Activity on the screenshot:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<ImageView
android:id="#+id/hexImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
If I replace wrap_content with value, hexagon as expected is changing its size.
Tested on Android 6.0 and 4.3.
Just one tip - instead of hardcoded values in getIntrinsicHeight() and getIntrinsicWidth(), it might be better to use dimens instead.

Progress bar with divider

Can someone please explain to me how to implement a progress bar with a divider just like its shown on the image below?
For the progress bar I am using https://github.com/akexorcist/Android-RoundCornerProgressBar but this does not seem to have a divider option.
replace ProgressDrawable from my answer with the modified one:
class ProgressDrawable extends Drawable {
private static final int NUM_SEGMENTS = 4;
private final int mForeground;
private final int mBackground;
private final Paint mPaint = new Paint();
private final RectF mSegment = new RectF();
public ProgressDrawable(int fgColor, int bgColor) {
mForeground = fgColor;
mBackground = bgColor;
}
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void draw(Canvas canvas) {
float level = getLevel() / 10000f;
Rect b = getBounds();
float gapWidth = b.height() / 2f;
float segmentWidth = (b.width() - (NUM_SEGMENTS - 1) * gapWidth) / NUM_SEGMENTS;
mSegment.set(0, 0, segmentWidth, b.height());
mPaint.setColor(mForeground);
for (int i = 0; i < NUM_SEGMENTS; i++) {
float loLevel = i / (float) NUM_SEGMENTS;
float hiLevel = (i + 1) / (float) NUM_SEGMENTS;
if (loLevel <= level && level <= hiLevel) {
float middle = mSegment.left + NUM_SEGMENTS * segmentWidth * (level - loLevel);
canvas.drawRect(mSegment.left, mSegment.top, middle, mSegment.bottom, mPaint);
mPaint.setColor(mBackground);
canvas.drawRect(middle, mSegment.top, mSegment.right, mSegment.bottom, mPaint);
} else {
canvas.drawRect(mSegment, mPaint);
}
mSegment.offset(mSegment.width() + gapWidth, 0);
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
and create it like this:
Drawable d = new ProgressDrawable(0xdd00ff00, 0x4400ff00);
/**
* Created by nagendra on 16/06/15.
*/
public class ProgressBarDrawable extends Drawable {
private int parts = 10;
private Paint paint = null;
private int fillColor = Color.parseColor("#2D6EB9");
private int emptyColor = Color.parseColor("#233952");
private int separatorColor = Color.parseColor("#FFFFFF");
private RectF rectFill = null;
private RectF rectEmpty = null;
private List<RectF> separators = null;
public ProgressBarDrawable(int parts)
{
this.parts = parts;
this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.separators = new ArrayList<RectF>();
}
#Override
protected boolean onLevelChange(int level)
{
invalidateSelf();
return true;
}
#Override
public void draw(Canvas canvas)
{
// Calculate values
Rect b = getBounds();
float width = b.width();
float height = b.height();
int spaceFilled = (int)(getLevel() * width / 10000);
this.rectFill = new RectF(0, 0, spaceFilled, height);
this.rectEmpty = new RectF(spaceFilled, 0, width, height);
int spaceBetween = (int)(width / 100);
int widthPart = (int)(width / this.parts - (int)(0.9 * spaceBetween));
int startX = widthPart;
for (int i=0; i<this.parts - 1; i++)
{
this.separators.add( new RectF(startX, 0, startX + spaceBetween, height) );
startX += spaceBetween + widthPart;
}
// Foreground
this.paint.setColor(this.fillColor);
canvas.drawRect(this.rectFill, this.paint);
// Background
this.paint.setColor(this.emptyColor);
canvas.drawRect(this.rectEmpty, this.paint);
// Separator
this.paint.setColor(this.separatorColor);
for (RectF separator : this.separators)
{
canvas.drawRect(separator, this.paint);
}
}
#Override
public void setAlpha(int alpha)
{
}
#Override
public void setColorFilter(ColorFilter cf)
{
}
#Override
public int getOpacity()
{
return PixelFormat.TRANSLUCENT;
}
}
in XM Layout
<ProgressBar
android:id="#+id/progress_bar_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="10"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
/>
ProgressBar progressBar= (ProgressBar)findViewById(R.id.progress_bar_test);
ProgressBarDrawable bgProgress= new ProgressBarDrawable(5);
progressBar.setProgressDrawable(bgProgress);
With the help of this and this answers, I could create my customized version of the segmented horizontal progress bar.
First, Create a class as follows.
public class SegmentedProgressDrawable extends Drawable {
private int parts;
private Paint paint;
private int fillColor;
private int emptyColor;
private int cutOffWidth;
private int separatorColor;
public SegmentedProgressDrawable(int parts, int fillColor, int emptyColor, int separatorColor) {
this.parts = parts;
this.fillColor = fillColor;
this.emptyColor = emptyColor;
this.separatorColor = separatorColor;
this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
#Override
protected boolean onLevelChange(int level) {
invalidateSelf();
return true;
}
#Override
public void draw(#NonNull Canvas canvas) {
// Calculate values
Rect bounds = getBounds();
float actualWidth = bounds.width();
float actualHeight = bounds.height();
//width with dividers + segment width
int fullBlockWidth = (int) (actualWidth / this.parts);
//ToDo: to change the width of segment change this line
int segmentWidth = (int) (fullBlockWidth * 0.2f);
// int dividerWidth =fullBlockWidth-segmentWidth;
cutOffWidth = (int) (getLevel() * actualWidth / 10000);
//Draw separator as background
RectF fullBox = new RectF(0, 0, actualWidth, actualHeight);
this.paint.setColor(this.separatorColor);
canvas.drawRect(fullBox, this.paint);
//start drawing lines as segmented bars
int startX = 0;
for (int i = 0; i < this.parts; i++) {
int endX = startX + segmentWidth;
//in ideal condition this would be the rectangle
RectF part = new RectF(startX, 0, endX, actualHeight);
//if the segment is below level the paint color should be fill color
if ((startX + segmentWidth) <= cutOffWidth) {
this.paint.setColor(this.fillColor);
canvas.drawRect(part, this.paint);
}
//if the segment is started below the level but ends above the level than we need to create 2 different rectangle
else if (startX < cutOffWidth) {
RectF part1 = new RectF(startX, 0, cutOffWidth, actualHeight);
this.paint.setColor(this.fillColor);
canvas.drawRect(part1, this.paint);
RectF part2 = new RectF(cutOffWidth, 0, startX + segmentWidth, actualHeight);
this.paint.setColor(this.emptyColor);
canvas.drawRect(part2, this.paint);
}
//if the segment is above level the paint color should be empty color
else {
this.paint.setColor(this.emptyColor);
canvas.drawRect(part, this.paint);
}
//update the startX to start the new segment with the gap of divider and segment width
startX += fullBlockWidth;
}
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(ColorFilter cf) {
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
And I, used it as follows:
horizontalProgressBar = findViewById(R.id.horizontal_progress_bar);
int fillColor = ContextCompat.getColor(getActivity(), R.color.primary);
int emptyColor = ContextCompat.getColor(getActivity(), R.color.color_redeem_badge_bg);
int separatorColor = ContextCompat.getColor(getActivity(), R.color.transparent);
SegmentedProgressDrawable progressDrawable = new SegmentedProgressDrawable(20, fillColor, emptyColor, separatorColor);
horizontalProgressBar.setProgressDrawable(progressDrawable);
horizontalProgressBar.setProgress(60);

How to draw lines in different colors?

I have developed an application which draws lines on the screen .I want to use different colors for the lines but all the lines are appearing in same color.
I have a color picker in my code to change the colors and i want to draw lines of different colors each time by selecting colors, but as of now since i am constructing lines and rendering it.When i choose initially red and draw a line, and then later select blue and draw a line , now the older line is also getting changed to blue instead of red, However i want the red to remain as red, and blue as such can any one help?
My code is given below
MyDemo.java:
public class MyDemo extends Activity implements
ColorPickerDialog.OnColorChangedListener {
private LinearLayout root;
private Button btnReset;
private Button btnPickColor;
public static int selectedColor = Color.BLACK;
MyImageView view;
private static final String COLOR_PREFERENCE_KEY = "color";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_demo);
root = (LinearLayout) findViewById(R.id.root);
btnReset = (Button) findViewById(R.id.reset);
btnPickColor = (Button) findViewById(R.id.pickColor);
final MyImageView view = new MyImageView(this);
view.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT));
root.addView(view);
btnReset.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
view.reset();
}
});
btnPickColor.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// color picker class call
int color = PreferenceManager.getDefaultSharedPreferences(
MyDemo.this).getInt(COLOR_PREFERENCE_KEY, Color.WHITE);
new ColorPickerDialog(MyDemo.this, MyDemo.this, color).show();
}
});
}
public void colorChanged(int color) {
PreferenceManager.getDefaultSharedPreferences(this).edit()
.putInt(COLOR_PREFERENCE_KEY, color).commit();
selectedColor = color;
}
}
MyImageView.java:
public class MyImageView extends ImageView implements View.OnTouchListener {
private int id = -1;
private Path path;
private List<Path> paths = new ArrayList<Path>();
private List<PointF> points = new ArrayList<PointF>();
boolean multiTouch = false;
MyDemo demo;
public MyImageView(Context context) {
super(context);
this.setOnTouchListener(this);
Log.d("Constructor", " Control in constructor");
}
public void reset() {
paths.clear();
points.clear();
path = null;
id = -1;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int colorPicked = MyDemo.selectedColor;
if (colorPicked != Color.BLACK) {
Paint paint = createPen(colorPicked);
paint.setStyle(Paint.Style.STROKE);
for (Path path : paths) {
canvas.drawPath(path, paint);
}
for (int i = 0; i < points.size(); i++) {
PointF p = points.get(i);
canvas.drawText("" + p.x, p.y, i, createPen(colorPicked));
}
} else {
Paint paint = createPen(colorPicked);
paint.setStyle(Paint.Style.STROKE);
for (Path path : paths) {
canvas.drawPath(path, paint);
}}
for (int i = 0; i < points.size(); i++) {
PointF p = points.get(i);
canvas.drawText("" + p.x, p.y, i, createPen(colorPicked));
}
}
private PointF copy(PointF p) {
PointF copy = new PointF();
copy.set(p);
return copy;
}
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
multiTouch = false;
id = event.getPointerId(0);
PointF p = getPoint(event, id);
path = new Path();
path.moveTo(p.x, p.y);
paths.add(path);
points.add(copy(p));
break;
case MotionEvent.ACTION_POINTER_DOWN:
multiTouch = true;
for (int i = 0; i < event.getPointerCount(); i++) {
int tId = event.getPointerId(i);
if (tId != id) {
points.add(getPoint(event, i));
}
}
break;
case MotionEvent.ACTION_MOVE:
if (!multiTouch) {
p = getPoint(event, id);
path.lineTo(p.x, p.y);
}
break;
}
invalidate();
return true;
}
private PointF getPoint(MotionEvent event, int i) {
int index = 0;
return new PointF(event.getX(index), event.getY(index));
}
public Paint createPen(int color) {
Paint pen = new Paint();
pen.setColor(color);
float width = 3;
pen.setStrokeWidth(width);
return pen;
}
}
ColorPickerDialog.java:
public class ColorPickerDialog extends Dialog {
public interface OnColorChangedListener {
void colorChanged(int color);
}
private final OnColorChangedListener mListener;
private final int mInitialColor;
private static class ColorPickerView extends View {
private final Paint mPaint;
private final Paint mCenterPaint;
private final int[] mColors;
private final OnColorChangedListener mListener;
ColorPickerView(Context c, OnColorChangedListener l, int color) {
super(c);
mListener = l;
mColors = new int[] { 0xFFFF0000, 0xFFFF00FF, 0xFF0000FF,
0xFF00FFFF, 0xFF00FF00, 0xFFFFFF00, 0xFFFF0000 };
Shader s = new SweepGradient(0, 0, mColors, null);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(s);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(32);
mCenterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mCenterPaint.setColor(color);
mCenterPaint.setStrokeWidth(5);
}
private boolean mTrackingCenter;
private boolean mHighlightCenter;
#Override
protected void onDraw(Canvas canvas) {
float r = CENTER_X - mPaint.getStrokeWidth() * 0.5f;
canvas.translate(CENTER_X, CENTER_X);
canvas.drawOval(new RectF(-r, -r, r, r), mPaint);
canvas.drawCircle(0, 0, CENTER_RADIUS, mCenterPaint);
if (mTrackingCenter) {
int c = mCenterPaint.getColor();
mCenterPaint.setStyle(Paint.Style.STROKE);
if (mHighlightCenter) {
mCenterPaint.setAlpha(0xFF);
} else {
mCenterPaint.setAlpha(0x80);
}
canvas.drawCircle(0, 0, CENTER_RADIUS
+ mCenterPaint.getStrokeWidth(), mCenterPaint);
mCenterPaint.setStyle(Paint.Style.FILL);
mCenterPaint.setColor(c);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(CENTER_X * 2, CENTER_Y * 2);
}
private static final int CENTER_X = 100;
private static final int CENTER_Y = 100;
private static final int CENTER_RADIUS = 32;
private int ave(int s, int d, float p) {
return s + java.lang.Math.round(p * (d - s));
}
private int interpColor(int colors[], float unit) {
if (unit <= 0)
return colors[0];
if (unit >= 1)
return colors[colors.length - 1];
float p = unit * (colors.length - 1);
int i = (int) p;
p -= i;
// now p is just the fractional part [0...1) and i is the index
int c0 = colors[i];
int c1 = colors[i + 1];
int a = ave(Color.alpha(c0), Color.alpha(c1), p);
int r = ave(Color.red(c0), Color.red(c1), p);
int g = ave(Color.green(c0), Color.green(c1), p);
int b = ave(Color.blue(c0), Color.blue(c1), p);
return Color.argb(a, r, g, b);
}
private static final float PI = 3.1415926f;
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX() - CENTER_X;
float y = event.getY() - CENTER_Y;
boolean inCenter = java.lang.Math.sqrt(x * x + y * y) <= CENTER_RADIUS;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTrackingCenter = inCenter;
if (inCenter) {
mHighlightCenter = true;
invalidate();
break;
}
case MotionEvent.ACTION_MOVE:
if (mTrackingCenter) {
if (mHighlightCenter != inCenter) {
mHighlightCenter = inCenter;
invalidate();
}
} else {
float angle = (float) java.lang.Math.atan2(y, x);
// need to turn angle [-PI ... PI] into unit [0....1]
float unit = angle / (2 * PI);
if (unit < 0) {
unit += 1;
}
mCenterPaint.setColor(interpColor(mColors, unit));
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (mTrackingCenter) {
if (inCenter) {
mListener.colorChanged(mCenterPaint.getColor());
}
mTrackingCenter = false; // so we draw w/o halo
invalidate();
}
break;
}
return true;
}
}
public ColorPickerDialog(Context context, OnColorChangedListener listener,
int initialColor) {
super(context);
mListener = listener;
mInitialColor = initialColor;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnColorChangedListener l = new OnColorChangedListener() {
public void colorChanged(int color) {
mListener.colorChanged(color);
dismiss();
}
};
LinearLayout layout = new LinearLayout(getContext());
layout.setOrientation(LinearLayout.VERTICAL);
layout.setGravity(Gravity.CENTER);
layout.setPadding(10, 10, 10, 10);
layout.addView(new ColorPickerView(getContext(), l, mInitialColor),
new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
setContentView(layout);
setTitle("Pick a Color");
}
}
I'm not sure but it seams a problem is in your onDraw method
Paint paint = createPen(colorPicked);
paint.setStyle(Paint.Style.STROKE);
for (Path path : paths) {
canvas.drawPath(path, paint);
}
You select a color first (it's the last color you picked) and then with a same color you draw each path.
I think that the solution for this could be to create array of colors which will contain color for every path you create and to pick corresponding color before you draw each path
try this, it will help you
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
int colorPicked = MainActivity.selectedColor;
paint1 = createPen(colorPicked);
for (Path p : paths){
canvas.drawPath(p, paint1);
paint1.setColor(colorPicked);
}
}
private Paint createPen(int color) {
// TODO Auto-generated method stub
paint1 = new Paint();
paint1.setAntiAlias(true);
paint1.setDither(true);
paint1.setStyle(Paint.Style.STROKE);
paint1.setStrokeJoin(Paint.Join.ROUND);
paint1.setStrokeCap(Paint.Cap.ROUND);
paint1.setStrokeWidth(3);
return paint1;
}

Categories

Resources