Is there a good way of drawing a path (or even just a straight line) on an android canvas where the line is in one color, but outlined with another? Here's what I'm looking to draw:
...the purpose of course being that the line (in my case a dashed line) is easily visible on both a black and white background.
Thanks!
You should first draw a thicker line with the color of the border, over it, you draw another line, at a distance of 1px to every side of the other line, so it will cover the first line, but 1 keeping visible 1px around the second line. something like this:
public void onDraw(Canvas canvas) {
float startX, startY, stopX, stopY;//remenber to inicialize them with actual values
int BORDER_COLOR, INNER_COLOR;//remenber to inicialize them with actual values
Paint paint = new Paint();
paint.setColor( BORDER_COLOR);
canvas.drawLine(startX, startY, stopX, stopY, paint);
paint.setColor( INNER_COLOR);
canvas.drawLine(startX+1, startY+1, stopX-1, stopY-1, paint);
}
draw twice: with different color and different stroke width
Related
I know how to stroke text using custom views(EditText or TextView) but I couldn't able to achieve something beautiful like this one, which is done using Photoshop. And yes, it has outer shadow too.
What I have done so far is adjusting stroke width and stroke join style. However, if I increase the stroke width, the stroke took place the whole text.
As far as I have searched, there is a library called MagicTextView but it also couldn't give the result like that above.
Update: I have tweaked things based on suggestion by #pskink. It works now. However I can't drag anymore. If I drag that EditText, there is some weird lines showed up like this.
Here is the code:
#Override public void onDraw(Canvas canvas) {
final int x = this.getLeft();
final int y = this.getBottom();
mText = this.getText().toString();
p.setStrokeWidth(30);
p.setStyle(Style.STROKE);
p.setStrokeJoin(Join.ROUND);
p.setColor(0xffffffff);
canvas.drawText(mText, x, y, p);
p.setStyle(Style.FILL);
p.setColor(0xff000000);
canvas.drawText(mText, x, y, p);
}
After a few hours of tweaking, I have fixed the weird line issue stated in updated question. I think I should post here as the answer.
#Override public void onDraw(Canvas canvas) {
mText = this.getText().toString();
p.setStyle(Style.STROKE);
p.setStrokeJoin(Join.ROUND);
p.setShadowLayer(10, 1, 1, 0xcfcccccc);
canvas.drawText(mText, 0, getLineHeight(), p);
p.clearShadowLayer();
p.setStrokeWidth(35);
p.setStrokeJoin(Join.ROUND);
p.setStyle(Style.STROKE);
p.setColor(0xffffffff);
canvas.drawText(mText, 0, getLineHeight(), p);
p.setStyle(Style.FILL);
p.setColor(0xff000000);
canvas.drawText(mText, 0, getLineHeight(), p);
canvas.translate(xPos, yPos);
}
xPos and yPos are x and y values from ACTION_MOVE onTouch event. And We need to add the line height as a Y for the canvas text.
However, if I increase the stroke width, the stroke took place the whole text.
If the problem is that the stroke is centered, and you want it outside the text, see: Android Paint stroke width positioning
You must precalculate the desired width and height according to your stroke.
I would suggest trying a very bold font. In the image below, the white stroke would be centered on the red line (which would be the outline of each black letter).
In response to your update:
If I drag that EditText, there is some weird lines showed up.
The line might be the result of focus on the EditText. You can remove the focus explicitly: Android: Force EditText to remove focus?
Alternatively, you can style the focus (perhaps to be invisible, if it doesn't adversely affect the rest of your UI): How to change the color of a focused EditText when using "android:Theme.Holo.Light"?
I can't just seem to figure it out. I am trying to draw a segmented circle (what looks like circle inside a circle). However I want the segments to have specific colors and to be transparent inside the smaller circle. Preferably , I would like to make the color of the segmented lines different than the circle
Here are the solutions I had in mind:
1- Draw arc with fill color for the bigger circle and draw a circle for the small circle. 2 problems with this. First one is that the inner circle area is no longer transparent as it takes the color from the bigger one. Second problem is that the segmentation lines of the outer circle is going all the way to the center (not only to the inner circle perimeter)
2) Draw arcs for the bigger outer circle and draw circle for the inner circle. Set it to be color filled but don't show strokes. Then draw another outer circle on top with no fill just to show strokes. And then draw lines between the inner and outer circle using the calculations ( angle and radius) to determine where the lines are... Very convoluted solution, there has to be another way. Even with this solution, still have problem with the color showing in the center but maybe playing with gradient can help.
I read so much on SO but I couldn't figure the right answer as many answers would remove the control of circle parameters
HEELP!!!
#Override
public void draw(Canvas canvas) {
float size = Math.min(getWidth(),getHeight());
paint.setStrokeWidth(size/4);
paint.setStyle(Paint.Style.STROKE);
final RectF oval = new RectF(0, 0, getWidth(), getHeight());
oval.inset(size/8,size/8);
paint.setColor(Color.RED);
Path redPath = new Path();
redPath.arcTo(oval, 0, 120, true);
canvas.drawPath(redPath, paint);
paint.setColor(Color.GREEN);
Path greenPath = new Path();
greenPath.arcTo(oval, 120, 120, true);
canvas.drawPath(greenPath, paint);
paint.setColor(Color.BLUE);
Path bluePath = new Path();
bluePath.arcTo(oval, 240, 120, true);
canvas.drawPath(bluePath, paint);
paint.setStrokeWidth(2);
paint.setColor(0xff000000);
canvas.save();
for(int i=0;i<360;i+=40){
canvas.rotate(40,size/2,size/2);
canvas.drawLine(size*3/4,size/2,size,size/2,paint);
}
canvas.restore();
final RectF ovalOuter = new RectF(0, 0, getWidth(), getHeight());
ovalOuter.inset(1,1);
canvas.drawOval(ovalOuter,paint);
final RectF ovalInner = new RectF(size/4, size/4, size*3/4,size*3/4);
canvas.drawOval(ovalInner,paint);
}
I'm drawing arcs using the Path class and strokes. Style.STROKE gives arcs without filling. Stroke width is set to size/4 which is a quarter of the view. Half of that stroke width goes outside and the second half goes inside, like this:
xxxxxxxx outer border of the arc of width 5
xxxxxxxx
------------ stroke
xxxxxxxx
xxxxxxxx inner border of the arc
That's why I'm using insets - I need to offset the stroke a bit in order to fit it in the view. Without insets the arcs are cut by all four sides of the view.
And why canvas rotation? Because it's easier to rotate the canvas with built-in methods than calculate lines manually. Rotation uses trigonometric functions and quickly becomes quite complex, hard to read and error prone. Basically I'm rotating the paper and drawing straight lines.
I have custom View that should paint a bitmap. I've created a simple line(bmp 1x50 px) to check where will be drawn exactly. In my onDraw(Canvas c) I'm using this line of code:
canvas.drawBitmap(bitmap, 0, 0, paint);
Where paint is simple Paint object, without any fancy settings. The problem is that this line shows at the middle of the view, not on top, as I thought it would be.
I'm setting View properties in layout xml:
<com.example.CustomView
android:id="#+id/costom_view"
android:layout_width="230px"
android:layout_height="188px"
android:layout_marginTop="10px"
custom:srcDraw="#drawable/menu_indicators_level_draw_up" />
This custom property is the ID of the bitmap I use to draw on canvas.
Why won't the View behave properly? And why does my canvas have a size if 800x450 (size of the screen i suppose) and not 230x188 like I defined in the layout?
And very important thing, I want to multiply the same bitmap on this view many times. At the end of work I want to draw this line from bottom to top of my View.
i think what you should use to draw the line above the bitmap is the follwing :
drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
and give it the right coordinates to be drawn on top of the bitmap .
Hope that helps .
How to "set up" a paint to accomplish the "second" image above?
paint.setColor(Color.BLACK);
canvas.drawText(strValue, x, y, paint);
First Image: text all in black as result of that code above.
Second Image: better constrat to backgroud colors (edited with graphic editor just to illustrate here)
Note that "31" is partially black and partially white (but it could be any other color with a better contrast to red, as "36" could be to blue).
You could draw with PixelXorXfermode.
the only solution I could think of is that first on your onDraw you have a variable Canvas that you equals to the actual one and then you draw your number,
paint.setColor(Color.BLACK);
canvas.drawText(strValue, x, y, paint);
then you draw the red Rect
canvas.drawRect(myRect, redPaint);
then you draw your line
canvas.drawline(mStartX,mStartY, mFinishX, mFinishY, myLinePaint);
and at the very end outside your onDraw, you call a method like this one:
public void myMethod(){
Paint paint = new Paint();
paint.setColor(Color.BLACK);
this.canvas.drawText(strValue, x, y, paint);
//here you will define the area that you will mark as dirty
//(wich can have the same values as your red Rect)
Rect myRect = new Rect();
myRect.set(x0,y0,x1,y1);
//and finally here you invalidate ONLY the red area
this.canvas.invalidate(myRect);
}
Note: this will require that on your onDraw you verify that the global Canvas is not null
and if so, then you equals your global to the actual.
I'm not sure if this will actually work, however is the only solution I could think of doing so.
PixelXorXfermode is not good method when AntiAlias is set.
if you can get the red rectangle, I think use canvas.clipRect is better. like this
textpaint.setColor(black);
canvas.drawText(str,x,y,textpaint);
Rect oldClipRect = canvas.getClipBounds();
canvas.clipRect(rcRed,Op.REPLACE);
textpaint.setColor(white);
canvas.drawText(str,x,y,textpaint);
canvas.clipRect(oldclipRect,Op.REPLACE);
How can I draw rectangle at start and end points but still maintain the same width? ie 10 pixels width.
Rect simplr = new Rect();
simplr.set(start.x, start.y, end.x, end.y);
thank you
Thickness is normally something you set in the Paint, not in the Rect.
See http://developer.android.com/reference/android/graphics/Paint.html#setStrokeWidth(float)