334

I'm trying to make a dotted line. I'm using this right now for a solid line:

LinearLayout divider = new LinearLayout( this );
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, 2 );
divider.setLayoutParams( params );
divider.setBackgroundColor( getResources().getColor( R.color.grey ) );

I need something like this, but dotted instead of solid. I'd like to avoid making hundreds of layouts alternating between a transparent layout and solid layout.

Jason Robinson
  • 31,005
  • 19
  • 77
  • 131

19 Answers19

705

Without java code:

drawable/dotted.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">

    <stroke
       android:color="#FF00FF"
       android:dashWidth="10px"
       android:dashGap="10px"
       android:width="1dp"/>
</shape>

view.xml:

<ImageView
    android:layout_width="match_parent"
    android:layout_height="5dp"
    android:src="@drawable/dotted"
    android:layerType="software" />

Effect: enter image description here

Boken
  • 4,825
  • 10
  • 32
  • 42
embo
  • 8,659
  • 1
  • 25
  • 23
  • 1
    This can also be done using just View instead of ImageView using android:background right? – Neil Mar 22 '13 at 17:22
  • 27
    I don't understand why I'm getting a line without gaps on my phone, while I'm seeing the gaps in the Graphical Layout in Eclipse. – Dante Apr 23 '13 at 11:46
  • 81
    Never mind, I've found the solution here : http://stackoverflow.com/questions/10843402/android-dashed-line-drawable-potential-ics-bug Just set layer type to software : android:layerType="software" – Dante Apr 23 '13 at 11:50
  • 7
    There is a [known bug](https://code.google.com/p/android/issues/detail?id=29944) when using `canvas.drawLine()`. As alternative to disable hardware acceleration, you can use `canvas.drawPath` instead. – hgoebl Dec 29 '13 at 16:32
  • regarding `canvas.drawPath()`, that only works reliably if all points are on screen due to a [known bug](https://code.google.com/p/android/issues/detail?id=24023) dating back to 2012. – snodnipper Apr 29 '15 at 22:30
  • After adding `android:layerType="software"` such things as Drawers starts lagging – Toochka Sep 08 '15 at 14:48
  • 13
    use `dp ` instead of `px `. – S.M_Emamian Feb 02 '16 at 04:24
  • 10
    Verified that this works on both Android 6.0.1 and 4.4.4. Two things to note: 1) you indeed need an ImageView, a View with the drawable as background didn't do it; 2) `android:layerType="software"` must be set on the ImageView. – Jonik Oct 26 '16 at 13:48
  • Thanks @hgoebl for the suggestion. Drawing paths does not require a software layer, which can be a huge advantage because otherwise large Views don't get rendered on the software layer with this error: "View not displayed because it is too large to fit into a software layer" – Saket Jun 20 '17 at 02:33
  • 1
    The secret is to add `android:layerType="software"` – André Luiz Reis Mar 16 '18 at 15:55
  • 4
    In my case, The `layout_height` of the `ImageView` must be larger than the `width` of the `Stroke`, if these values equal, the dash line will disappear. – ZhangLei Apr 17 '19 at 09:49
  • is there any way to make it work in flutter? i know that flutter don't support xml. But using flutter_svg package we can make around to work with svg files. anyone with any suggestion? – VeeyaaR Feb 19 '20 at 06:51
  • 1
    @ZhangLei yes thanks and I found wrap_content height didn't work either – hmac Oct 19 '20 at 09:37
  • without `ImageView`? just using `View` and `background`? – user924 Nov 04 '22 at 19:32
245

The path effect is set on the paint object

Paint fgPaintSel = new Paint();
fgPaintSel.setARGB(255, 0, 0,0);
fgPaintSel.setStyle(Style.STROKE);
fgPaintSel.setPathEffect(new DashPathEffect(new float[] {10f,20f}, 0f));

You can create all sorts of dotted patterns by supplying more numbers in the int[] array which specifies the ratios of dash and gap. This is a simple, equally dashed, line.

Aldan
  • 674
  • 9
  • 23
siliconeagle
  • 7,379
  • 3
  • 29
  • 41
68

Creating dotted line using XML.
Create xml in drawable folder and give that background to the item to which you want to set dotted border.

Creating XML Background "dashed_border":

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape>
            <solid android:color="#ffffff" />
            <stroke
                android:dashGap="5dp"
                android:dashWidth="5dp"
                android:width="1dp"
                android:color="#0000FF" />
            <padding
                android:bottom="5dp"
                android:left="5dp"
                android:right="5dp"
                android:top="5dp" />
        </shape>
    </item>
</layer-list>

Adding that background to item:

<Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/dashed_border"/>
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Sargam
  • 987
  • 1
  • 8
  • 6
  • If you need radius for corners, just add `` to your shape. See https://stackoverflow.com/a/41940609/1000551 for more info – Vadim Kotov Jul 22 '19 at 10:55
  • 3
    I think the layer-list is unnecessary for a single item. I used the as the root element and it works the same. – big_m Aug 21 '19 at 16:48
43

Create xml (view_line_dotted.xml):

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:bottom="-1dp"
            android:left="-1dp"
            android:right="-1dp"
            android:top="0dp">

            <shape android:shape="rectangle">
                <stroke
                    android:width="1dp"
                    android:color="#ffff0017"
                    android:dashGap="3dp"
                    android:dashWidth="1dp" />

                <solid android:color="@android:color/transparent" />

                <padding
                    android:bottom="10dp"
                    android:left="10dp"
                    android:right="10dp"
                    android:top="10dp" />
            </shape>
        </item>
</layer-list>

Set as background of your view:

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@drawable/view_line_dotted" />
Mohammad Ersan
  • 12,304
  • 8
  • 54
  • 77
tier777
  • 1,005
  • 12
  • 11
  • Can you explain it please? – skywall Jul 13 '15 at 13:56
  • 1
    Thanks, the clue is ``, if you want a horizontal line 1dp thickness. – CoolMind Aug 01 '19 at 11:57
  • Awesome. Nearly works out of the box for me. The only change I needed was to change the stroke tag; 2dp width and 4dp dashGap. – Sufian Oct 02 '19 at 07:57
  • For devices with API < 21 add `android:layerType="software"` into a view or write `view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)` (see https://stackoverflow.com/questions/10843402/android-dashed-line-drawable-potential-ics-bug). – CoolMind Nov 28 '19 at 09:44
28

What I did when I wanted to draw a dotted line is to define a drawable dash_line.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="line">

    <stroke
        android:width="1dp"
        android:color="@color/black"
        android:dashWidth="2dp"
        android:dashGap="3dp" />
</shape>

And then in the layout just define a view with background as dash_line. Note to include android:layerType="software", otherwise it won't work.

<View
    android:layout_width="match_parent"
    android:layout_height="5dp"
    android:background="@drawable/dash_line"
    android:layerType="software" />
Aldan
  • 674
  • 9
  • 23
Tony Vu
  • 4,251
  • 3
  • 31
  • 38
25

I have custom dash line which support horizontal & vertical dash line. Code below:

public class DashedLineView extends View
{
    private float density;
    private Paint paint;
    private Path path;
    private PathEffect effects;

    public DashedLineView (Context context)
    {
        super(context);
        init(context);
    }

    public DashedLineView (Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init(context);
    }

    public DashedLineView (Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context)
    {
        density = DisplayUtil.getDisplayDensity(context);
        paint = new Paint ();
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(density * 4);
        //set your own color
        paint.setColor(context.getResources().getColor(R.color.XXX));
        path = new Path ();
        //array is ON and OFF distances in px (4px line then 2px space)
        effects = new DashPathEffect (new float [] { 4, 2, 4, 2 }, 0);

    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        paint.setPathEffect(effects);
        int measuredHeight = getMeasuredHeight ();
        int measuredWidth = getMeasuredWidth ();
        if (measuredHeight <= measuredWidth) {
            // horizontal
            path.moveTo(0, 0);
            path.lineTo(measuredWidth, 0);
            canvas.drawPath(path, paint);
        } else {
            // vertical
            path.moveTo(0, 0);
            path.lineTo(0, measuredHeight);
            canvas.drawPath(path, paint);
        }

    }
}
Aldan
  • 674
  • 9
  • 23
ruidge
  • 1,149
  • 1
  • 15
  • 14
16

If you are looking for a vertical line use this drawable.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:top="-8dp"
        android:bottom="-8dp"
        android:left="-8dp">
        <shape>
            <solid android:color="@android:color/transparent"/>
            <stroke
                android:width="4dp"
                android:color="#ffffff"
                android:dashGap="4dp"
                android:dashWidth="4dp"/>
        </shape>
    </item>
</layer-list>

The negative top bottom and left values remove the unwanted sides of the shape leaving a single dashed line.

Use it in a view like so.

<View
android:layout_width="4dp"
android:layout_height="match_parent"
android:background="@drawable/dash_line_vertical"
android:layerType="software" />
P. Medas
  • 35
  • 1
  • 5
Duncan Hoggan
  • 5,082
  • 3
  • 23
  • 29
12

By using this class you can apply "dashed and underline" effect to multiple lines text. to use DashPathEffect you have to turn off hardwareAccelerated of your TextView(though DashPathEffect method has a problem with long text). you can find my sample project here: https://github.com/jintoga/Dashed-Underlined-TextView/blob/master/Untitled.png.

public class DashedUnderlineSpan implements LineBackgroundSpan, LineHeightSpan {

    private Paint paint;
    private TextView textView;
    private float offsetY;
    private float spacingExtra;

    public DashedUnderlineSpan(TextView textView, int color, float thickness, float dashPath,
                               float offsetY, float spacingExtra) {
        this.paint = new Paint();
        this.paint.setColor(color);
        this.paint.setStyle(Paint.Style.STROKE);
        this.paint.setPathEffect(new DashPathEffect(new float[] { dashPath, dashPath }, 0));
        this.paint.setStrokeWidth(thickness);
        this.textView = textView;
        this.offsetY = offsetY;
        this.spacingExtra = spacingExtra;
    }

    @Override
    public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v,
                             Paint.FontMetricsInt fm) {
        fm.ascent -= spacingExtra;
        fm.top -= spacingExtra;
        fm.descent += spacingExtra;
        fm.bottom += spacingExtra;
    }

    @Override
    public void drawBackground(Canvas canvas, Paint p, int left, int right, int top, int baseline,
                               int bottom, CharSequence text, int start, int end, int lnum) {
        int lineNum = textView.getLineCount();
        for (int i = 0; i < lineNum; i++) {
            Layout layout = textView.getLayout();
            canvas.drawLine(layout.getLineLeft(i), layout.getLineBottom(i) - spacingExtra + offsetY,
                    layout.getLineRight(i), layout.getLineBottom(i) - spacingExtra + offsetY,
                    this.paint);
        }
    }
}

Result:

dashed underline

carla
  • 1,970
  • 1
  • 31
  • 44
Nguyen Quoc Dat
  • 201
  • 3
  • 7
7

For a Dotted effect on a Canvas, set this attribute to the paint object :

paint.setPathEffect(new DashPathEffect(new float[] {0,30}, 0));

And change the value 30 as your render suits you : it represents the "distance" between each dots.

enter image description here

Arnaud
  • 408
  • 4
  • 11
5

I have created dashed dotted line for EditText. Here you go. Create your new xml. e.g dashed_border.xml Code here:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:bottom="1dp"
    android:left="-2dp"
    android:right="-2dp"
    android:top="-2dp">
    <shape android:shape="rectangle">
        <stroke
            android:width="2dp"
            android:color="#000000"
            android:dashGap="3dp"
            android:dashWidth="1dp" />

        <solid android:color="#00FFFFFF" />

        <padding
            android:bottom="10dp"
            android:left="10dp"
            android:right="10dp"
            android:top="10dp" />
    </shape>
</item></layer-list>

And use your new xml file in your EditText for example:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/dashed_border"/>

Cheers! :)

4

I have used the below as a background for the layout:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <stroke
        android:width="1dp"
        android:color="android:@color/black"
        android:dashWidth="10px"
        android:dashGap="10px" />
</shape>
Aldan
  • 674
  • 9
  • 23
udai
  • 3,723
  • 4
  • 16
  • 20
4

I liked the solution from Ruidge, but I needed more control from XML. So I changed it to Kotlin and added attributes.

1) Copy the Kotlin class:

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View

class DashedDividerView : View {
constructor(context: Context) : this(context, null, 0)
constructor(context: Context, attributeSet: AttributeSet) : this(context, attributeSet, 0)

companion object {
    const val DIRECTION_VERTICAL = 0
    const val DIRECTION_HORIZONTAL = 1
}

private var dGap = 5.25f
private var dWidth = 5.25f
private var dColor = Color.parseColor("#EE0606")
private var direction = DIRECTION_HORIZONTAL
private val paint = Paint()
private val path = Path()

constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
    context,
    attrs,
    defStyleAttr
) {
    val typedArray = context.obtainStyledAttributes(
        attrs,
        R.styleable.DashedDividerView,
        defStyleAttr,
        R.style.DashedDividerDefault
    )

    dGap = typedArray.getDimension(R.styleable.DashedDividerView_dividerDashGap, dGap)
    dWidth = typedArray.getDimension(R.styleable.DashedDividerView_dividerDashWidth, dWidth)
    dColor = typedArray.getColor(R.styleable.DashedDividerView_dividerDashColor, dColor)
    direction =
        typedArray.getInt(R.styleable.DashedDividerView_dividerDirection, DIRECTION_HORIZONTAL)

    paint.color = dColor
    paint.style = Paint.Style.STROKE
    paint.pathEffect = DashPathEffect(floatArrayOf(dWidth, dGap), 0f)
    paint.strokeWidth = dWidth

    typedArray.recycle()
}

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    path.moveTo(0f, 0f)

    if (direction == DIRECTION_HORIZONTAL) {
        path.lineTo(measuredWidth.toFloat(), 0f)
    } else {
        path.lineTo(0f, measuredHeight.toFloat())
    }
    canvas.drawPath(path, paint)
}

}

2) Create an attr file in the /res directory and add this

 <declare-styleable name="DashedDividerView">
    <attr name="dividerDashGap" format="dimension" />
    <attr name="dividerDashWidth" format="dimension" />
    <attr name="dividerDashColor" format="reference|color" />
    <attr name="dividerDirection" format="enum">
        <enum name="vertical" value="0" />
        <enum name="horizontal" value="1" />
    </attr>
</declare-styleable>

3) Add a style to the styles file

 <style name="DashedDividerDefault">
    <item name="dividerDashGap">2dp</item>
    <item name="dividerDashWidth">2dp</item>
    <!-- or any color -->
    <item name="dividerDashColor">#EE0606</item>
    <item name="dividerDirection">horizontal</item>
</style>

4) Now you can use the default style

<!-- here will be your path to the class -->
<com.your.package.app.DashedDividerView
    android:layout_width="match_parent"
    android:layout_height="2dp"
    />

or set attributes in XML

<com.your.package.app.DashedDividerView
    android:layout_width="match_parent"
    android:layout_height="2dp"
    app:dividerDirection="horizontal"
    app:dividerDashGap="2dp"
    app:dividerDashWidth="2dp"
    app:dividerDashColor="@color/light_gray"/>
Igor
  • 51
  • 1
4

None of these answers worked for me. Most of these answers give you a half-transparent border. To avoid this, you need to wrap your container once again with another container with your preferred color. Here is an example:

This is how it looks

dashed_border_layout.xml

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@color/black"
android:background="@drawable/dashed_border_out">
<LinearLayout
    android:layout_width="150dp"
    android:layout_height="50dp"
    android:padding="5dp"
    android:background="@drawable/dashed_border_in"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is&#10;Dashed Container"
        android:textSize="16sp" />
</LinearLayout>

dashed_border_in.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape>
        <corners android:radius="10dp" />
        <solid android:color="#ffffff" />
        <stroke
            android:dashGap="5dp"
            android:dashWidth="5dp"
            android:width="3dp"
            android:color="#0000FF" />
        <padding
            android:bottom="5dp"
            android:left="5dp"
            android:right="5dp"
            android:top="5dp" />
    </shape>
</item>

dashed_border_out.xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape>
        <corners android:radius="12dp" />
    </shape>
</item>

Yunus Emre
  • 390
  • 3
  • 9
3

The only thing that worked for me and I think it is the simplest way is using a Path with a paint object like this:

    Paint paintDash = new Paint();
    paintDash.setARGB(255, 0, 0, 0);
    paintDash.setStyle(Paint.Style.STROKE);
    paintDash.setPathEffect(new DashPathEffect(new float[]{10f,10f}, 0));
    paintDash.setStrokeWidth(2);
    Path pathDashLine = new Path();

Then onDraw(): (important call reset if you change those points between ondraw calls, cause Path save all the movements)

    pathDashLine.reset();
    pathDashLine.moveTo(porigenX, porigenY);
    pathDashLine.lineTo(cursorX,cursorY);
    c.drawPath(pathDashLine, paintDash);
takluiper
  • 679
  • 2
  • 8
  • 24
3

Use a ShapeDrawable instead of a LinearLayout and play with dashWidth and dashGap

http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape

vieux
  • 23,887
  • 3
  • 26
  • 26
2

Best Solution for Dotted Background working perfect

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
  <stroke
    android:dashGap="3dp"
    android:dashWidth="2dp"
    android:width="1dp"
    android:color="@color/colorBlack" />
</shape>
WindRider
  • 11,958
  • 6
  • 50
  • 57
Arun Prajapati
  • 283
  • 2
  • 6
1

I dont know why but the voted answers don't work for me. I write it this way and works good.
Define a custom view:

public class XDashedLineView extends View {

private Paint   mPaint;
private Path    mPath;
private int     vWidth;
private int     vHeight;

public XDashedLineView(Context context) {
    super(context);
    init();
}

public XDashedLineView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public XDashedLineView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init() {
    mPaint = new Paint();
    mPaint.setColor(Color.parseColor("#3F577C"));
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setPathEffect(new DashPathEffect(new float[] {10,10}, 0));
    mPath = new Path();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    this.vWidth = getMeasuredWidth();
    this.vHeight = getMeasuredHeight();
    mPath.moveTo(0, this.vHeight / 2);
    mPath.quadTo(this.vWidth / 2, this.vHeight / 2, this.vWidth, this.vHeight / 2);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawPath(mPath, mPaint);
}
}

Then you can use it in your xml:

        <com.YOUR_PACKAGE_NAME.XDashedLineView
        android:layout_width="690dp"
        android:layout_height="1dp"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="620dp"/>
Kyeson
  • 960
  • 1
  • 6
  • 17
1

I've created a library with a custom view to solve this issue, and it should be very simple to use. See https://github.com/Comcast/DahDit for more. You can add dashed lines like this:

<com.xfinity.dahdit.DashedLine
    android:layout_width="250dp"
    android:layout_height="wrap_content"
    app:dashHeight="4dp"
    app:dashLength="8dp"
    app:minimumDashGap="3dp"
    app:layout_constraintRight_toRightOf="parent"
    android:id="@+id/horizontal_dashes"/>
Calvin
  • 450
  • 2
  • 10
  • Thanks for sharing. I'm going to have to refine it for my use case, but this is exactly what I needed to get started with custom views. Cheers. –  Jun 17 '19 at 13:07
1

Similar to tier777 here is a solution for a horizontal line:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:top="-1dp">
        <shape android:shape="line">
            <stroke
                android:width="1dp"
                android:color="#111"
                android:dashWidth="8dp"
                android:dashGap="2dp"
                />
            <solid android:color="@android:color/transparent" />
        </shape>
    </item>
</layer-list>

The clue is <item android:top="-1dp">.

In order to show dashed line on old devices (<= API 21) you should create a view with android:layerType="software" (see Android dashed line drawable potential ICS bug):

<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@drawable/dashed_line"
    android:layerType="software"
    />

Also you can add the same view without android:layerType="software" to layout-v23 for better performance, but I am not sure it will work on all devices with API 23.

CoolMind
  • 26,736
  • 15
  • 188
  • 224