javaandroidandroid-canvasandroid-paint

Paint attributes are not working on Canvas


I am trying to create the white impact font with black outline (aka "The Meme Font"). I applied the logic for both texts that are drawn on Canvas but it works only for one of them. Here is a result to show what I'm talking about:

enter image description here

Here is my code:

        Canvas canvas = new Canvas(mutableBitmap);

        TextPaint topFillPaint = new TextPaint();
        TextPaint bottomFillPaint = new TextPaint();

        TextPaint topStrokePaint = new TextPaint();
        TextPaint bottomStrokePaint = new TextPaint();

        Typeface typeface = getResources().getFont(R.font.impact);

        topFillPaint.setColor(Color.WHITE);
        topFillPaint.setTextSize(topTextView.getTextSize());
        topFillPaint.setTypeface(typeface);

        topStrokePaint.setStyle(Paint.Style.STROKE);
        topStrokePaint.setStrokeWidth(8);
        topStrokePaint.setColor(Color.BLACK);
        topStrokePaint.setTextSize(topTextView.getTextSize());
        topStrokePaint.setTypeface(typeface);

        bottomFillPaint.setColor(Color.WHITE);
        bottomFillPaint.setTextSize(bottomTextView.getTextSize());
        bottomFillPaint.setTypeface(typeface);

        bottomStrokePaint.setStyle(Paint.Style.STROKE);
        bottomStrokePaint.setStrokeWidth(8);
        bottomStrokePaint.setColor(Color.BLACK);
        bottomStrokePaint.setTextSize(bottomTextView.getTextSize());
        bottomStrokePaint.setTypeface(typeface);

        float topTextMeasurement = topFillPaint.measureText(topText);
        float bottomTextMeasurement = bottomFillPaint.measureText(bottomText);

        StaticLayout topFillLayout = new StaticLayout(topText, topFillPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER,
                1.0f, 0.0f, false);
        StaticLayout topStrokeLayout = new StaticLayout(topText, topStrokePaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER,
                1.0f, 0.0f, false);


        StaticLayout bottomFillLayout = new StaticLayout(bottomText, bottomFillPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER,
                1.0f, 0.0f, false);
        StaticLayout bottomStrokeLayout = new StaticLayout(bottomText, bottomStrokePaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER,
                1.0f, 0.0f, false);

        canvas.translate(0,0);
        topFillLayout.draw(canvas);

        canvas.translate(0,0);
        topStrokeLayout.draw(canvas);

        canvas.translate(0, canvas.getHeight() - 210);
        bottomFillLayout.draw(canvas);

        canvas.translate(0, canvas.getHeight() - 210);
        bottomStrokeLayout.draw(canvas);

UPDATE

I've commented out

canvas.translate(0, canvas.getHeight() - 210); and bottomFillLayout.draw(canvas); and the black border was drawn. So either the fill text covers the outline or the outline doesn't exist when fill text is drawn.


Solution

  • To get the behavior you want, you'd just remove the second canvas.translate(0, canvas.getHeight() - 210);.

    The canvas.translate calls adjust the current translation of the Canvas (it adds to the translation, it doesn't reset it absolutely). This means that canvas.translate(0, 0); is actually a no-op because it doesn't change the translation at all (these lines can just be removed). The translation does not reset after draw calls so this means that your second canvas.translate(0, canvas.getHeight() - 210); call is translating off of the screen (unless your screen height is less than 210 * 2).

    See the android.graphics.Canvas documentation of the translate method for more information.