Android textview outline text

So, little late, but MagicTextView will do text outlines, amongst other things.

enter image description here

<com.qwerjk.better_text.MagicTextView
    xmlns:qwerjk="http://schemas.android.com/apk/res/com.qwerjk.better_text"
    android:textSize="78dp"
    android:textColor="#ff333333"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    qwerjk:strokeColor="#FFff0000"
    qwerjk:strokeJoinStyle="miter"
    qwerjk:strokeWidth="5"
    android:text="Magic" />

Note: I made this, and am posting more for the sake of future travelers than the OP. It's borderline spam, but being on-topic, perhaps acceptable?


outline effect can be achieved using shadow in TextView:

    android:shadowColor="#000000"
    android:shadowDx="1.5"
    android:shadowDy="1.3"
    android:shadowRadius="1.6"
    android:text="CCC"
    android:textAllCaps="true"
    android:textColor="@android:color/white"

It is quite an old question but still I don't see any complete answers. So I am posting this solution, hoping that someone struggling with this problem might find it useful. The simplest and most effective solution is to override TextView class' onDraw method. Most implementations I have seen use drawText method to draw the stroke but that approach doesn't account for all the formatting alignment and text wrapping that goes in. And as a result often the stroke and text end up at different places. Following approach uses super.onDraw to draw both the stroke and fill parts of the text so you don't have to bother about rest of the stuff. Here are the steps

  1. Extend TextView class
  2. Override onDraw method
  3. Set paint style to FILL
  4. call parent class on Draw to render text in fill mode.
  5. save current text color.
  6. Set current text color to your stroke color
  7. Set paint style to Stroke
  8. Set stroke width
  9. And call parent class onDraw again to draw the stroke over the previously rendered text.

    package com.example.widgets;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Typeface;
    import android.util.AttributeSet;
    import android.widget.Button;
    
    public class StrokedTextView extends Button {
    
        private static final int DEFAULT_STROKE_WIDTH = 0;
    
        // fields
        private int _strokeColor;
        private float _strokeWidth;
    
        // constructors
        public StrokedTextView(Context context) {
            this(context, null, 0);
        }
    
        public StrokedTextView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public StrokedTextView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
    
            if(attrs != null) {
                TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.StrokedTextAttrs);
                _strokeColor = a.getColor(R.styleable.StrokedTextAttrs_textStrokeColor,
                        getCurrentTextColor());         
                _strokeWidth = a.getFloat(R.styleable.StrokedTextAttrs_textStrokeWidth,
                        DEFAULT_STROKE_WIDTH);
    
                a.recycle();
            }
            else {          
                _strokeColor = getCurrentTextColor();
                _strokeWidth = DEFAULT_STROKE_WIDTH;
            } 
            //convert values specified in dp in XML layout to
            //px, otherwise stroke width would appear different
            //on different screens
            _strokeWidth = dpToPx(context, _strokeWidth);           
        }    
    
        // getters + setters
        public void setStrokeColor(int color) {
            _strokeColor = color;        
        }
    
        public void setStrokeWidth(int width) {
            _strokeWidth = width;
        }
    
        // overridden methods
        @Override
        protected void onDraw(Canvas canvas) {
            if(_strokeWidth > 0) {
                //set paint to fill mode
                Paint p = getPaint();
                p.setStyle(Paint.Style.FILL);        
                //draw the fill part of text
                super.onDraw(canvas);       
                //save the text color   
                int currentTextColor = getCurrentTextColor();    
                //set paint to stroke mode and specify 
                //stroke color and width        
                p.setStyle(Paint.Style.STROKE);
                p.setStrokeWidth(_strokeWidth);
                setTextColor(_strokeColor);
                //draw text stroke
                super.onDraw(canvas);      
               //revert the color back to the one 
               //initially specified
               setTextColor(currentTextColor);
           } else {
               super.onDraw(canvas);
           }
       }
    
       /**
        * Convenience method to convert density independent pixel(dp) value
        * into device display specific pixel value.
        * @param context Context to access device specific display metrics 
        * @param dp density independent pixel value
        * @return device specific pixel value.
        */
       public static int dpToPx(Context context, float dp)
       {
           final float scale= context.getResources().getDisplayMetrics().density;
           return (int) (dp * scale + 0.5f);
       }            
    }
    

That is all. This class uses custom XML attributes to enable specifying stroke color and width from the XML layout files. Therefore, you need to add these attributes in your attr.xml file in subfolder 'values' under folder 'res'. Copy and paste the following in your attr.xml file.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="StrokedTextAttrs">
        <attr name="textStrokeColor" format="color"/>    
        <attr name="textStrokeWidth" format="float"/>
    </declare-styleable>                

</resources>

Once you are done with that, you can use the custom StrokedTextView class in your XML layout files and specify stroke color and width as well. Here is an example

<com.example.widgets.StrokedTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Stroked text sample"
    android:textColor="@android:color/white"
    android:textSize="25sp"
    strokeAttrs:textStrokeColor="@android:color/black"
    strokeAttrs:textStrokeWidth="1.7" />

Remember to replace package name with your project's package name. Also add the xmlns namespace in the layout file in order to use custom XML attributes. You can add the following line in your layout file's root node.

xmlns:strokeAttrs="http://schemas.android.com/apk/res-auto"

You can put a shadow behind the text, which can often help readability. Try experimenting with 50% translucent black shadows on your green text. Details on how to do this are over here: Android - shadow on text?

To really add a stroke around the text, you need to do something a bit more involved, like this: How do you draw text with a border on a MapView in Android?