Come faccio a creare una linea tratteggiata / tratteggiata in Android?


254

Sto cercando di creare una linea tratteggiata. Sto usando questo adesso per una linea continua:

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

Ho bisogno di qualcosa del genere, ma punteggiato anziché solido. Vorrei evitare di alternare centinaia di layout tra un layout trasparente e un layout solido.

Risposte:


517

Senza codice 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" />

21
Non capisco perché sto ricevendo una linea senza lacune sul mio telefono, mentre sto vedendo le lacune nel Layout grafico in Eclipse.
Dante,

73
Non importa, ho trovato la soluzione qui: stackoverflow.com/questions/10843402/… Basta impostare il tipo di layer sul software: android: layerType = "software"
Dante,

7
Esiste un bug noto durante l'utilizzo canvas.drawLine(). In alternativa per disabilitare l'accelerazione hardware, è possibile utilizzare canvas.drawPathinvece.
hgoebl,

10
utilizzare dp invece di px .
S.M_Emian

7
Verificato che funziona su Android 6.0.1 e 4.4.4. Due cose da notare: 1) hai davvero bisogno di un ImageView, una vista con il disegno come sfondo non lo ha fatto; 2) android:layerType="software"deve essere impostato su ImageView.
Jonik,

206

l'effetto del tracciato è impostato sull'oggetto di disegno

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

puoi creare tutti i tipi di modelli punteggiati fornendo più numeri nell'array int [] che specifica i rapporti di trattino e gap. Questa è una linea semplice, ugualmente tratteggiata.


perché questo ora fa per me? stackoverflow.com/questions/12401311/...
Chris.Zou

prova il nuovo float [] {5,10,15,20} nel costruttore
siliconeagle

4
Sono leggermente nuovo nello sviluppo Android. Voglio chiedere come viene aggiunto l'oggetto di disegno con effetto tratteggiato al layout lineare che ho appena creato?
Dirk Jan

Ho copiato e incollato questo codice direttamente, ma non è successo nulla. Devo scrivere un codice aggiuntivo per farlo funzionare?
Jason,

50

Creazione di linea tratteggiata tramite XML.
Crea xml in una cartella disegnabile e dai lo sfondo all'elemento su cui vuoi impostare il bordo tratteggiato.

Creazione dello sfondo XML "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>

Aggiungendo quello sfondo all'elemento:

<Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/dashed_border"/>

Se hai bisogno di un raggio per gli angoli, aggiungi semplicemente la <corners android:radius="5dp" />tua forma. Vedi stackoverflow.com/a/41940609/1000551 per maggiori informazioni
Vadim Kotov

Penso che l'elenco dei livelli non sia necessario per un singolo elemento. Ho usato <shape> come elemento radice e funziona allo stesso modo.
big_m

37

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

Imposta come sfondo della vista:

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@drawable/view_line_dotted" />

Puoi spiegarlo per favore?
skywall,

1
Grazie, la chiave è che <item android:bottom="-1dp" android:left="-1dp" android:right="-1dp" >se si desidera uno spessore di 1dp di linea orizzontale.
CoolMind

Eccezionale. Per me funziona quasi fuori dagli schemi. L'unica modifica di cui avevo bisogno era cambiare il tag del tratto; Larghezza 2dp e trattino 4Dp.
Sufian,

Per i dispositivi con API <21 aggiungi android:layerType="software"in una vista o scrivi view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)(vedi stackoverflow.com/questions/10843402/… ).
CoolMind,

24

Quello che ho fatto quando volevo disegnare una linea tratteggiata è definire un dash_line.xml disegnabile :

<?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 poi nel layout basta definire una vista con sfondo come dash_line . Nota per includere android: layerType = "software" , altrimenti non funzionerà.

<View
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:background="@drawable/dash_line"
            android:layerType="software" />

Grazie compagno! La android:layerType="software"è la cosa che stavo cercando! Saluti!
Toochka,

20

Ho personalizzato una linea che supporta la linea orizzontale e verticale. codice qui sotto:

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

}
}

Questo approccio è preferibile rispetto alla forma XML?
IgorGanapolsky,

Perfetto! quello che stavo cercando
Giobbe M

9

Utilizzando questa classe è possibile applicare l'effetto "tratteggiato e sottolineato" a più righe di testo. per usare DashPathEffect devi disattivare hardwareAccelerated di TextView (sebbene il metodo DashPathEffect abbia un problema con il testo lungo). puoi trovare il mio progetto di esempio qui: 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);
        }
    }
}

Risultato:

sottolineato tratteggiato


8

Se stai cercando una linea verticale usa questo disegno.

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

I valori in alto a sinistra in basso e a sinistra rimuovono i lati indesiderati della forma lasciando un'unica linea tratteggiata.

Usalo in una vista del genere.

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

4

Ho usato il seguito come sfondo per il 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>

Perché android:shape="rectangle"invece della linea?
IgorGanapolsky,

4

Ho creato una linea tratteggiata tratteggiata per EditText. Ecco qui. Crea il tuo nuovo XML. es. dashed_border.xml Codice qui:

<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 usa ad esempio il tuo nuovo file XML nel tuo EditText:

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

Saluti! :)



3

La migliore soluzione per lo sfondo punteggiato funziona perfettamente

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

3

Per un effetto Punteggiato su una tela, imposta questo attributo sull'oggetto pittura:

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

E cambia il valore 30 secondo il tuo rendering: rappresenta la "distanza" tra ogni punto.

inserisci qui la descrizione dell'immagine


2

L'unica cosa che ha funzionato per me e penso che sia il modo più semplice è usare un Path con un oggetto paint come questo:

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

Quindi onDraw (): (importante ripristino delle chiamate se si cambiano quei punti tra le chiamate di prelievo, perché Path salva tutti i movimenti)

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

2

Mi è piaciuta la soluzione di Ruidge , ma avevo bisogno di un maggiore controllo da XML. Quindi l'ho cambiato in Kotlin e ho aggiunto degli attributi.

1) Copia la 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) Creare un file attr nella directory / res e aggiungerlo

 <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) Aggiungi uno stile al file degli stili

 <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) Ora puoi usare lo stile predefinito

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

o imposta gli attributi 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"/>

2

Nessuna di queste risposte ha funzionato per me. La maggior parte di queste risposte ti dà un bordo semitrasparente. Per evitare ciò, è necessario avvolgere nuovamente il contenitore con un altro contenitore con il colore preferito. Ecco un esempio:

Ecco come appare

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>


1

Non so perché, ma le risposte votate non funzionano per me. Lo scrivo in questo modo e funziona bene.
Definire una vista personalizzata:

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

Quindi puoi usarlo nel tuo XML:

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

1

Ho creato una libreria con una vista personalizzata per risolvere questo problema e dovrebbe essere molto semplice da usare. Vedi https://github.com/Comcast/DahDit per ulteriori informazioni. Puoi aggiungere linee tratteggiate in questo modo:

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

Grazie per la condivisione. Devo perfezionarlo per il mio caso d'uso, ma questo è esattamente ciò di cui avevo bisogno per iniziare con le visualizzazioni personalizzate. Saluti.

0

Simile a tier777 ecco una soluzione per una linea orizzontale:

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

L'indizio è <item android:top="-1dp">.

Per mostrare la linea tratteggiata su vecchi dispositivi (<= API 21) è necessario creare una vista con android:layerType="software"(vedi potenziale bug ICS tracciabile per la linea tratteggiata 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"
    />

Inoltre è possibile aggiungere la stessa vista, senza android:layerType="software"per layout-v23per migliorare le prestazioni, ma non sono sicuro che funzionerà su tutti i dispositivi con API 23.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.