Pavel Dudka
Pavel Dudka

Reputation: 20934

Stroke cap for custom PathEffect

I'm implementing custom path effect for route on top of MapView and I came up with the problem how to make my beginning and ending of the path rounded (like Paint.setStrokeCap(Cap.ROUND) does). See screenshot - black lines - is my route I want to round at the end

Here is how I implemented my custom PathEffect:

public RouteOverlay(Context context)
{
    mContext = context;

    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setColor(COLOR_DEFAULT);
    mPaint.setAntiAlias(true);
    mPaint.setStrokeCap(Cap.ROUND); // this one does not work...
    mPaint.setStrokeJoin(Join.ROUND);
    PathEffect e1 = new PathDashPathEffect(createRouteLineStyle(), 10, 3, PathDashPathEffect.Style.MORPH);
    PathEffect e2 = new CornerPathEffect(10);
    mPaint.setPathEffect(new ComposePathEffect(e1, e2));
}

private Path createRouteLineStyle() 
{
    Path p = new Path();
    p.moveTo(-5, ROUTE_LINE_WIDTH/2);
    p.lineTo(5,ROUTE_LINE_WIDTH/2);
    p.lineTo(5,ROUTE_LINE_WIDTH/2-currentThickness);
    p.lineTo(-5, ROUTE_LINE_WIDTH/2-currentThickness);
    p.close();
    p.moveTo(-5, -(ROUTE_LINE_WIDTH/2));
    p.lineTo(5,-(ROUTE_LINE_WIDTH/2));
    p.lineTo(5, -(ROUTE_LINE_WIDTH/2-currentThickness));
    p.lineTo(-5, -(ROUTE_LINE_WIDTH/2-currentThickness));
    return p;
}

@Override
public void draw(Canvas canvas, final MapView mapView, boolean shadow)
{
    if(shadow) return;

    if(mDrawEnabled)
    {
        synchronized(mPoints)
        {
            canvas.drawPath(mPath, mPaint);
        }
    }
}

As you can see on the screenshot, the ending of the line is not rounded (as well as beginning...). setStrokeCap(Cap.ROUND) doesn't help.

So the question is - how to add round cap to my custom path? I was thinking of using addArc() or addCircle() to the end (and beginning) of my path, but this doesn't seem right.

The reason why I need custom path effect - is that I need to draw the route around actual road - so route should be empty inside and have inner and outer stroke lines.

In case somebody knows how to make this kind of path effect in some other way - please let me know, because this solution has big cons I have to deal with..

No stroke cap

Upvotes: 1

Views: 5860

Answers (2)

Pavel Dudka
Pavel Dudka

Reputation: 20934

I managed to find a solution for my problem. So I got rid of my custom path effect and started to use usual stroke (where stroke cap works as expected). 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.

@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

Upvotes: 2

shri046
shri046

Reputation: 1198

I don't see any reason why that should not work unless you are running into the problem mentioned here http://code.google.com/p/android/issues/detail?id=24873.

Upvotes: 2

Related Questions