Como faço para criar uma linha pontilhada / tracejada no Android?

254

Estou tentando fazer uma linha pontilhada. Estou usando isso agora para uma linha sólida:

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 ) );

Eu preciso de algo assim, mas pontilhado em vez de sólido. Eu gostaria de evitar fazer centenas de layouts alternando entre um layout transparente e um layout sólido.

Jason Robinson
fonte

Respostas:

517

Sem código java:

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="#C7B299"
       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" />
embo
fonte
21
Não entendo por que estou recebendo uma linha sem lacunas no meu telefone, enquanto vejo as lacunas no Layout Gráfico no Eclipse.
Dante
73
Nunca mente, eu encontrei a solução aqui: stackoverflow.com/questions/10843402/... apenas definir tipo de camada de software: android: layerType = "software"
Dante
7
Há um erro conhecido ao usar canvas.drawLine(). Como alternativa para desativar a aceleração de hardware, você pode usar canvas.drawPath.
hgoebl
10
use em dp vez de px .
S.M_Emamian 02/02
7
Verificou que isso funciona no Android 6.0.1 e 4.4.4. Duas coisas a serem observadas: 1) você realmente precisa de um ImageView, um View com o drawable como plano de fundo não o fez; 2) android:layerType="software"deve estar definido no ImageView.
26616 Jonik
206

o efeito do caminho é definido no objeto de pintura

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

você pode criar todos os tipos de padrões pontilhados fornecendo mais números na matriz int [] que especifica as proporções de traço e intervalo. Esta é uma linha simples, igualmente tracejada.

siliconeagle
fonte
por que isso faz agora para mim? stackoverflow.com/questions/12401311/…
Chris.Zou
tente novo flutuador [] {5,10,15,20} no construtor
siliconeagle
4
Eu sou um pouco novo no desenvolvimento do Android. Quero perguntar como o objeto de pintura com efeito tracejado é adicionado ao layout linear que acabei de criar?
Dirkjan
Copiei e colei esse código diretamente, mas nada aconteceu. Devo escrever um código extra para fazê-lo funcionar?
Jason
50

Criando linha pontilhada usando XML.
Crie xml na pasta drawable e dê esse plano de fundo ao item ao qual você deseja definir a borda pontilhada.

Criando 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>

Adicionando esse plano de fundo ao item:

<Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/dashed_border"/>
Sargam
fonte
Se você precisar de raio para cantos, basta adicionar <corners android:radius="5dp" />à sua forma. Veja stackoverflow.com/a/41940609/1000551 para obter mais informações
Vadim Kotov
Eu acho que a lista de camadas é desnecessária para um único item. Eu usei o <shape> como elemento raiz e funciona da mesma maneira.
big_m 21/08/19
37

Crie 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>

Defina como plano de fundo da sua exibição:

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@drawable/view_line_dotted" />
tier777
fonte
Você pode explicar isso por favor?
Skywall
1
Obrigado, a dica é <item android:bottom="-1dp" android:left="-1dp" android:right="-1dp" >, se você quiser uma linha horizontal de 1dp de espessura.
CoolMind 01/08/19
Impressionante. Quase funciona imediatamente para mim. A única mudança que eu precisava era mudar a etiqueta do traçado; 2dp de largura e 4dp dashGap.
Sufian
Para dispositivos com API <21, adicione android:layerType="software"em uma exibição ou gravação view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)(consulte stackoverflow.com/questions/10843402/… ).
CoolMind #
24

O que fiz quando quis desenhar uma linha pontilhada é definir um dash_line.xml desenhável :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
    android:shape="line" >
<stroke
    android:dashGap="3dp"
    android:dashWidth="2dp"
    android:width="1dp"
    android:color="@color/black" />
</shape>

E então, no layout, apenas defina uma visualização com fundo como dash_line . Nota para incluir android: layerType = "software" , caso contrário não funcionará.

<View
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:background="@drawable/dash_line"
            android:layerType="software" />
Tony Vu
fonte
Obrigado companheiro! A android:layerType="software"coisa que eu estava procurando! Felicidades!
Toochka 29/07
20

Eu tenho um traço personalizado que suporta linha de traço horizontal e vertical. código abaixo:

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);
    }

}
}
Ruidge
fonte
Essa abordagem é preferível ao formato xml?
IgorGanapolsky
perfeito! o que eu estava procurando
Job M
9

Ao usar esta classe, você pode aplicar o efeito "tracejado e sublinhado" a várias linhas de texto. Para usar o DashPathEffect, é necessário desativar o hardwareAccelerated do seu TextView (embora o método DashPathEffect tenha um problema com o texto longo). você pode encontrar meu projeto de amostra aqui: 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);
        }
    }
}

Resultado:

sublinhado tracejado

Nguyen Quoc Dat
fonte
8

Se você estiver procurando por uma linha vertical, use este 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>

Os valores inferior esquerdo e superior negativos removem os lados indesejados da forma, deixando uma única linha tracejada.

Use-o em uma exibição como essa.

<View
android:layout_width="4dp"
android:layout_height="match_parent"
android:background="@drawable/dash_line_vertical"
android:layerType="software" />
Duncan Hoggan
fonte
4

Eu usei o abaixo como pano de fundo para o 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:dashWidth="10px"
   android:dashGap="10px"
    android:color="android:@color/black" 
   />
</shape>
udai
fonte
Por que em android:shape="rectangle"vez de linha?
IgorGanapolsky
4

Eu criei uma linha pontilhada tracejada para EditText. Aqui está. Crie seu novo xml. por exemplo, dashed_border.xml Código aqui:

<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>

E use seu novo arquivo xml no seu EditText, por exemplo:

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

Felicidades! :)

Wiktor Kalinowski
fonte
3

Melhor Solução para o Fundo Pontilhado funcionando perfeitamente

<?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>
Arun Prajapati
fonte
3

Para um efeito Pontilhado em uma Tela, defina este atributo para o objeto de pintura:

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

E altere o valor 30 conforme sua renderização combina com você: representa a "distância" entre cada ponto.

insira a descrição da imagem aqui

Arnaud
fonte
2

A única coisa que funcionou para mim e acho que é a maneira mais simples é usar um Path com um objeto de pintura como este:

    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();

Em seguida, onDraw (): (redefinição de chamada importante se você alterar esses pontos entre as chamadas ondraw, pois o Path salvará todos os movimentos)

    pathDashLine.reset();
    pathDashLine.moveTo(porigenX, porigenY);
    pathDashLine.lineTo(cursorX,cursorY);
    c.drawPath(pathDashLine, paintDash);
takluiper
fonte
2

Gostei da solução da Ruidge , mas precisava de mais controle do XML. Então mudei para Kotlin e adicionei atributos.

1) Copie a classe Kotlin:

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) Crie um arquivo attr no diretório / res e adicione este

 <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) Adicione um estilo ao arquivo de estilos

 <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) Agora você pode usar o estilo padrão

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

ou defina atributos em 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
fonte
2

Nenhuma dessas respostas funcionou para mim. A maioria dessas respostas fornece uma borda semitransparente. Para evitar isso, você precisa embrulhar seu contêiner mais uma vez com outro contêiner da sua cor preferida. Aqui está um exemplo:

Isto é o que parece

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
fonte
1

Não sei por que, mas as respostas votadas não funcionam para mim. Escrevo assim e funciona bem.
Defina uma visualização personalizada:

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);
}
}

Então você pode usá-lo em seu xml:

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

Criei uma biblioteca com uma exibição personalizada para resolver esse problema e deve ser muito simples de usar. Consulte https://github.com/Comcast/DahDit para obter mais informações. Você pode adicionar linhas tracejadas como esta:

<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
fonte
Obrigado por compartilhar. Vou precisar refiná-lo para o meu caso de uso, mas é exatamente isso que eu precisava para começar com visualizações personalizadas. Felicidades.
0

Semelhante ao tier777, aqui está uma solução para uma linha horizontal:

<?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>

A pista é <item android:top="-1dp">.

Para mostrar a linha tracejada em dispositivos antigos (<= API 21), você deve criar uma visualização com android:layerType="software"(consulte o bug potencial do ICS desenhável na linha tracejada do Android ):

<?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"
    />

Também é possível adicionar o mesmo ponto de vista, sem android:layerType="software"que layout-v23para um melhor desempenho, mas não estou certo de que vai funcionar em todos os dispositivos com API 23.

CoolMind
fonte