I'm trying to make a wheel of colours which allows the user to select between Solid color or Gradients.
The user can also move those colours around the wheel.
The problem is with the gradient. When the angle is over 360° the colour displayed is going back to the first colour instead of continue the gradient.
I'm using a custom view and the code I will paste is called from the onDraw method.
int start = Color.rgb((int)previous.startRed, (int)previous.startGreen, (int)previous.startBlue);
int end = Color.rgb((int)previous.endRed, (int)previous.endGreen, (int)previous.endBlue);
int[] colors = {start, end, end};
float from = from_angle / 360.0f;
float to = (from_angle + to_angle) / 360.0f;
float[] positions = {from,to, to};
Log.v("Print", "print positions " + positions[0] + " " + positions[1]);
Shader gradient = new SweepGradient (oval.centerX(), oval.centerY(),colors, positions);
paint.setShader(gradient);
canvas.drawArc(oval, from_angle, to_angle + 1, false, paint);
Here is a picture to show the problem I face.
Any hint would be appreciated. Thank you.
Related
I'm trying to draw a text to the screen and then have a rectangle in the same spot to account for knowing when the user clicks within it (and clicks the text). Problem is when I put the text in one spot on the screen and the rectangle in the same spot, it apparently isn't in the same spot. Is there some setting I need to set somewhere?
private final String[] options = {"Start", "High Scores", "Help", "Quit"};
public void draw(final Canvas g)
{
for (int i = 0; i < options.length; i++)
{
width = HORIZONTALOFFSET * 3 + spaceInvadersTitle.getWidth();
height = GamePanel.getScreenHeight() / 4 - (75 * 2 + TEXT_SIZE) / 2 + i * 75;
rect[i] = new Rect(width, height, width + 325, height + TEXT_SIZE);
g.drawRect(rect[i], paint);
g.drawText(options[i], width, height, paint);
}
}
FYI "width" and "height" are more like x- and y-coords. The horizontal alignment is not the problem - just the vertical. If you'll notice from the code, I'm setting the starting x- and y-coordinates for the drawText and drawRect the same exact position, but that's not how they're showing on the screen. Instead it seems the drawText is using that position as a lowerleft anchorpoint or something like that. Is that how it works? If so, how do I change that?
Also, if you have any suggestions on how to approach listening for when the user clicks on a drawn text, I'm all ears. This is the easiest way I could think of, and how I do it in regular desktop Java.
I have a custom view, around which I want to draw a path, like a border.
But the border should draw itself gradually, like a snake growing in size.
The aim is to use it as a timer for a player to make his move in a game.
I used the Path class and the methods lineTo and addArc to draw the border.
timerPath = new Path();
timerPath.moveTo(getTranslationX() + width / 2, getTranslationY() + 3);
timerPath.lineTo(getTranslationX() + width - 10, getTranslationY() + 3);
timerPath.addArc(new RectF(getTranslationX() + width - 20, getTranslationY() + 3,
getTranslationX() + width - 3, getTranslationY() + 20), -90f, 90f);
...
...
timerPath.lineTo(getTranslationX() + width / 2, getTranslationY() + 3);
timerPaint = new Paint();
timerPaint.setColor(Color.GREEN);
timerPaint.setStyle(Paint.Style.STROKE);
timerPaint.setStrokeWidth(6);
I use the drawPath() method in onDraw:
canvas.drawPath(timerPath, timerPaint);
It looks well.
Now, I wonder if there is a way to draw just part of the path using percentage (10%, 11%, 12% .. etc).
Then I'll be able to animate the drawing.
If it's not possible, is there another way of animating border drawing? (to use as a timer)
Appreciate your help.
You can use the PathMeasure class to do this. Create a PathMeasure object from your path, measure the length and then use getSegment() to return a partial path that you can draw to the canvas:
float percentage = 50.0f; // initialize to your desired percentage
PathMeasure measure = new PathMeasure(timerPath, false);
float length = measure.getLength();
Path partialPath = new Path();
measure.getSegment(0.0f, (length * percentage) / 100.0f, partialPath, true);
partialPath.rLineTo(0.0f, 0.0f); // workaround to display on hardware accelerated canvas as described in docs
canvas.drawPath(partialPath, timerPaint);
I need to draw something like this:
I was hoping that this guy posted some code of how he drew his segmented circle to begin with, but alas he didn't.
I also need to know which segment is where after interaction with the wheel - for instance if the wheel is rotated, I need to know where the original segments are after the rotation action.
Two questions:
Do I draw this segmented circle (with varying colours and content placed on the segment) with OpenGL or using Android Canvas?
Using either of the options, how do I register which segment is where?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDIT:
Ok, so I've figured out how to draw the segmented circle using Canvas (I'll post the code as an answer). And I'm sure I'll figure out how to rotate the circle soon. But I'm still unsure how I'll recognize a separate segment of the drawn wheel after the rotation action.
Because, what I'm thinking of doing is drawing the segmented circle with these wedges, and the sort of handling the entire Canvas as an ImageView when I want to rotate it as if it's spinning. But when the spinning stops, how do I differentiate between the original segments drawn on the Canvas?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I've read about how to draw a segment on its own (here also), OpenGL, Canvas and even drawing shapes and layering them, but I've yet to see someone explaining how to recognize the separate segments.
Can drawBitmap() or createBitmap() perhaps be used?
If I go with OpenGL, I'll probably be able to rotate the segmented wheel using OpenGL's rotation, right?
I've also read that OpenGL might be too powerful for what I'd like to do, so should I rather consider "the graphic components of a game library built on top of OpenGL"?
This kind of answers my first question above - how to draw the segmented circle using Android Canvas:
Using the code found here, I do this in the onDraw function:
// Starting values
private int startAngle = 0;
private int numberOfSegments = 11;
private int sweepAngle = 360 / numberOfSegments;
#Override
protected void onDraw(Canvas canvas) {
setUpPaint();
setUpDrawingArea();
colours = getColours();
Log.d(TAG, "Draw the segmented circle");
for (int i = 0; i < numberOfSegments; i++) {
// pick a colour that is not the previous colour
paint.setColor(colours.get(pickRandomColour()));
// Draw arc
canvas.drawArc(rectF, startAngle, sweepAngle, true, paint);
// Set variable values
startAngle -= sweepAngle;
}
}
This is how I set up the drawing area based on the device's screen size:
private void setUpDrawingArea() {
Log.d(TAG, "Set up drawing area.");
// First get the screen dimensions
Point size = new Point();
Display display = DrawArcActivity.this.getWindowManager().getDefaultDisplay();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.d(TAG, "Screen size = "+width+" x "+height);
// Set up the padding
int paddingLeft = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
int paddingTop = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
int paddingRight = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
int paddingBottom = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
// Then get the left, top, right and bottom Xs and Ys for the rectangle we're going to draw in
int left = 0 + paddingLeft;
int top = 0 + paddingTop;
int right = width - paddingRight;
int bottom = width - paddingBottom;
Log.d(TAG, "Rectangle placement -> left = "+left+", top = "+top+", right = "+right+", bottom = "+bottom);
rectF = new RectF(left, top, right, bottom);
}
That (and the other functions which are pretty straight forward, so I'm not going to paste the code here) draws this:
The segments are different colours with every run.
I want to draw a green point with the text in the sample code of android opengl: spritetext(the code please visit the following site: https://gitorious.org/0xdroid/development/source/9ca6f2c0573e7c6e76515be664e633f03a1a4358:samples/ApiDemos/src/com/example/android/apis/graphics/spritetext/LabelMaker.java).
I added the following code in the function: public int add(GL10 gl, Drawable background, String text, Paint textPaint,
int minWidth, int minHeight) of the LakerMarker.java:
Paint p = new Paint();
p.setColor(Color.GREEN);
p.setStrokeWidth(20);
if (drawText) {
mCanvas.drawText(text,
u + padding.left + centerOffsetWidth,
vBase + padding.top + centerOffsetHeight,
textPaint);// in the sample code, just this.
mCanvas.drawPoint( u + padding.left + centerOffsetWidth,
vBase + padding.top + centerOffsetHeight,
p);// this code is to draw the green point
}
Then I run, get the following image result.I want to only the left green point with each text, but there were two points(one is in left, another one is in right) with each text, How to deal with this problem? Thanks in advance!
I'm painting text over a background image on a canvas. I move the image interactively (like a Ouija board pointer). I've set the canvas to black, the pointer is red and I want to write white text over it so that the pointer has a player's name on it.
In Android 2.3.4 it appears as solid white text on top of the red pointer which is pretty clear, but I'd like to use any color. In Android 4.1.2 I can barely see the white text. Here's my code:
public Pointer(Context context) {
super(context);
paintBg = new Paint();
paintBg.setColor(Color.BLACK);
paintName = new Paint();
paintName.setColor(Color.WHITE);
paintName.setTextSize(50); // set text size
paintName.setStrokeWidth(5);
paintName.setTextAlign(Paint.Align.CENTER);
this.setImageResource(res); // pointer.png in res/drawable folder
Drawable d = getResources().getDrawable(res);
h = d.getIntrinsicHeight();
w = d.getIntrinsicWidth();
canvas = new Canvas();
canvas.drawPaint(paintBg);//make background black
// float imageScale = width / w; // how image size scales with screen
}
#Override
public void onDraw(Canvas canvas) {
y = this.getHeight() / 2; // center of screen
x = this.getWidth() / 2;
int left = Math.round(x - 0.8f * w);
int right = Math.round(x + 0.8f * w);
canvas.save();
canvas.rotate((direction + 180) % 360, x, y); // rotate to normal
canvas.drawText(s, x, y + 20, paintName); // draw name
canvas.restore();
canvas.rotate(direction, x, y); // rotate back
super.onDraw(canvas);
}
What changed in 4.1.2 that would affect this, or am I doning something incorrectly? Thanks for your help with this as it's driving me crazy.
Edit to include screen shots:
Android 2.3.4
Android 4.1.2
Note how the white text appears to be on top in 2.3.4 while it appears below or muddy in 4.1.2.
As free3dom pointes out it is related to alpha. I do change alpha because if I don't, the text does not appear on top of the arrow. It appears that the ImageView having the pointer image is always on top - could this be what's going on?
Here is how I handle setting alpha:
public static void setAlpha(View view, float alpha, int duration) {
if (Build.VERSION.SDK_INT < 11) {
final AlphaAnimation animation = new AlphaAnimation(alpha, alpha);
animation.setDuration(duration);
animation.setFillAfter(true);
view.startAnimation(animation);
} else //for 11 and above
view.setAlpha(alpha);
}
Maybe it has something to do with using this.setImageResource(res) to set the image resource? According to android developer guide, I can only set alpha to the single view and everything in the view is changed. Yet if I lower the alpha, the arrow image seems to become transparent enough to allow me to see the text.
You set a stroke width, but never indicate that stroke should be used for the Paint.
Try adding
paintName.setStyle( FILL_AND_STROKE );