10

I'm currently working on map overlay which highlights the route along specified points and I need to implement certain line style (something like on screenshot)

route indication What I'm trying to do - is to highlight the route with something like transparent line with black stroke lines from both sides

Playing with different fill styles and Paint settings haven't led me to any solution so far.

Does anybody know what direction I need to look for?

Currently I managed to draw only solid line, but this is not what I'm looking for:

Paint setup:

mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(COLOR_DEFAULT); mPaint.setPathEffect(new CornerPathEffect(10)); mPaint.setStrokeWidth(6); mPaint.setAntiAlias(true); 

Drawing routine

canvas.drawPath(mPath, mPaint); 
1
  • Use two Paints and do two draw passes, one for FILL and one for STROKE. Commented Jun 6, 2012 at 2:18

2 Answers 2

34

I get pretty good results with PathDashPathEffect using a "dash stamp" that's two very thin rectangles and the MORPH style option. See last and 3rd last line here:

enter image description here

This was drawn by modifying the PathEffects example in ApiDemos taken from the SDK:

package com.example.android.apis.graphics; import android.content.Context; import android.graphics.*; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; public class PathEffects extends GraphicsActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private Paint mPaint; private Path mPath; private PathEffect[] mEffects; private int[] mColors; private float mPhase = 3; private static void makeEffects(PathEffect[] e, float phase) { e[0] = null; // no effect e[1] = new CornerPathEffect(10); e[2] = new DashPathEffect(new float[] {10, 5, 5, 5}, phase); e[3] = new PathDashPathEffect(makePathDash(), 12, phase, PathDashPathEffect.Style.MORPH); e[4] = new ComposePathEffect(e[2], e[1]); e[5] = new ComposePathEffect(e[3], e[1]); } public SampleView(Context context) { super(context); setFocusable(true); setFocusableInTouchMode(true); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(6); mPath = makeFollowPath(); mEffects = new PathEffect[6]; mColors = new int[] { Color.BLACK, Color.RED, Color.BLUE, Color.GREEN, Color.MAGENTA, Color.BLACK }; } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); RectF bounds = new RectF(); mPath.computeBounds(bounds, false); canvas.translate(10 - bounds.left, 10 - bounds.top); makeEffects(mEffects, mPhase); invalidate(); for (int i = 0; i < mEffects.length; i++) { mPaint.setPathEffect(mEffects[i]); mPaint.setColor(mColors[i]); canvas.drawPath(mPath, mPaint); canvas.translate(0, 28); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: mPath = makeFollowPath(); return true; } return super.onKeyDown(keyCode, event); } private static Path makeFollowPath() { Path p = new Path(); p.moveTo(0, 0); for (int i = 1; i <= 15; i++) { p.lineTo(i*20, (float)Math.random() * 35); } return p; } private static Path makePathDash() { Path p = new Path(); p.moveTo(-6, 4); p.lineTo(6,4); p.lineTo(6,3); p.lineTo(-6, 3); p.close(); p.moveTo(-6, -4); p.lineTo(6,-4); p.lineTo(6,-3); p.lineTo(-6, -3); return p; } } } 
Sign up to request clarification or add additional context in comments.

7 Comments

Nice answer! thanks! What if I want to set the background color of the last line? Is that possible? I would like to make the border black and fill it with blue
Can we increase the width of the lines in the last line of the image?
@user1294668 Sure, but I don't know how smooth the result will look. The makePathDash method is drawing what looks like an equal sign where the the strokes are rectangles 2 pixels tall (y-coordinates +-3 and +- 4). Just make them taller.
@Gene Here's the method I'm using. It's increasing the spacing between the lines. I want the stroke width of both to be increased. How to do it? private static Path makePathDash() { Path p = new Path(); p.moveTo(-6, 8); p.lineTo(6,8); p.lineTo(6,7); p.lineTo(-6, 7); p.close(); p.moveTo(-6, -8); p.lineTo(6,-8); p.lineTo(6,-7); p.lineTo(-6, -7); return p; }
@user1294668 You want something like (-6,6) (6,6) (6,3) (-6,3) and similar for the other side.
|
1

I managed to find a better solution for my problem. So I got rid of my custom path effect and started to use usual stroke. So I basically draw my path 2 times: at first I draw black line, after that I draw thiner transparent line to clear the center of previous black line.

The only trick in this approach is that I need to draw my path in a separate bitmap (using temp canvas) and when path bitmap is ready - render it to the main canvas.

Hope this will help somebody else

@Override public void draw(Canvas canvas, final MapView mapView, boolean shadow) { //Generate new bitmap if old bitmap doesn't equal to the screen size (f.i. when screen orientation changes) if(pathBitmap == null || pathBitmap.isRecycled() || pathBitmap.getWidth()!=canvas.getWidth() || pathBitmap.getHeight()!=canvas.getHeight()) { if(pathBitmap != null) { pathBitmap.recycle(); } pathBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888); tempCanvas.setBitmap(pathBitmap); } //Render routes to the temporary bitmap renderPathBitmap(); //Render temporary bitmap onto main canvas canvas.drawBitmap(pathBitmap, 0, 0, null); } } private void renderPath(Path path, Canvas canvas) { routePaint.setStrokeWidth(ROUTE_LINE_WIDTH); routePaint.setColor(OUTER_COLOR); routePaint.setXfermode(null); canvas.drawPath(path, routePaint); //render outer line routePaint.setStrokeWidth(ROUTE_LINE_WIDTH/1.7f); routePaint.setColor(Color.TRANSPARENT); routePaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR)); canvas.drawPath(path, routePaint); //render inner line } 

So result looks like:

enter image description here

1 Comment

I can't get it working on OSM maps. Here's the code I'm using. It doesn't draw anything. if(pathBitmap == null || pathBitmap.isRecycled() || pathBitmap.getWidth()!=canvas.getWidth() || pathBitmap.getHeight()!=canvas.getHeight()) { if(pathBitmap != null) { pathBitmap.recycle(); } pathBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888); tempCanvas = new Canvas(pathBitmap); } tempCanvas .drawPath(path, routePaint); canvas.drawBitmap(pathBitmap, 0, 0, null);

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.