Comment créer une ligne pointillée / pointillée dans Android?

254

J'essaie de faire une ligne pointillée. J'utilise ceci en ce moment pour une ligne continue:

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

J'ai besoin de quelque chose comme ça, mais pointillé au lieu de solide. Je voudrais éviter de faire des centaines de mises en page alternant entre une mise en page transparente et une mise en page solide.

Jason Robinson
la source

Réponses:

517

Sans code 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
la source
21
Je ne comprends pas pourquoi je reçois une ligne sans lacunes sur mon téléphone, alors que je vois les lacunes dans la disposition graphique dans Eclipse.
Dante
73
Peu importe, j'ai trouvé la solution ici: stackoverflow.com/questions/10843402/… Définissez simplement le type de calque sur logiciel: android: layerType = "software"
Dante
7
Il existe un bogue connu lors de l'utilisation canvas.drawLine(). Comme alternative pour désactiver l'accélération matérielle, vous pouvez utiliser à la canvas.drawPathplace.
hgoebl
10
utiliser dp au lieu de px .
S.M_Emamian
7
Vérifié que cela fonctionne sur Android 6.0.1 et 4.4.4. Deux choses à noter: 1) vous avez en effet besoin d'une ImageView, une vue avec le dessinable comme arrière-plan ne l'a pas fait; 2) android:layerType="software"doit être défini sur ImageView.
Jonik
206

l'effet de trajectoire est défini sur l'objet de peinture

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

vous pouvez créer toutes sortes de motifs en pointillés en fournissant plus de nombres dans le tableau int [], il spécifie les rapports de tiret et d'espace. Il s'agit d'une ligne simple, également en pointillés.

siliconeeagle
la source
pourquoi cela fait maintenant pour moi? stackoverflow.com/questions/12401311/…
Chris.Zou
essayez un nouveau float [] {5,10,15,20} dans le constructeur
siliconeagle
4
Je suis légèrement nouveau dans le développement Android. Je veux demander comment l'objet de peinture avec effet en pointillés est ajouté à la disposition linéaire que je viens de créer?
DirkJan
J'ai copié et collé ce code directement, mais rien ne s'est produit. Dois-je écrire du code supplémentaire pour le faire fonctionner?
jason
50

Création d'une ligne pointillée à l'aide de XML.
Créez du xml dans un dossier dessinable et donnez cet arrière-plan à l'élément auquel vous souhaitez définir une bordure en pointillés.

Création d'un arrière-plan 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>

Ajout de cet arrière-plan à l'élément:

<Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/dashed_border"/>
Sargam
la source
Si vous avez besoin d'un rayon pour les coins, ajoutez simplement <corners android:radius="5dp" />à votre forme. Voir stackoverflow.com/a/41940609/1000551 pour plus d'informations
Vadim Kotov
Je pense que la liste des calques n'est pas nécessaire pour un seul élément. J'ai utilisé le <shape> comme élément racine et cela fonctionne de la même manière.
big_m
37

Créez du 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>

Définissez comme arrière-plan de votre vue:

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@drawable/view_line_dotted" />
tier777
la source
Pouvez-vous l'expliquer s'il vous plaît?
skywall
1
Merci, l'indice est <item android:bottom="-1dp" android:left="-1dp" android:right="-1dp" >, si vous voulez une épaisseur de ligne horizontale 1dp.
CoolMind
Impressionnant. Fonctionne presque hors de la boîte pour moi. Le seul changement dont j'avais besoin était de changer l'étiquette de trait; Largeur 2dp et dashGap 4dp.
Sufian
Pour les appareils avec API <21, ajoutez android:layerType="software"dans une vue ou écrivez view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)(voir stackoverflow.com/questions/10843402/… ).
CoolMind
24

Ce que j'ai fait quand j'ai voulu dessiner une ligne pointillée, c'est définir un dash_line.xml dessinable :

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

Et puis dans la mise en page, définissez simplement une vue avec un arrière-plan en tant que dash_line . Remarque pour inclure android: layerType = "software" , sinon cela ne fonctionnera pas.

<View
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:background="@drawable/dash_line"
            android:layerType="software" />
Tony Vu
la source
Merci mon pote! C'est android:layerType="software"la chose que je cherchais! À votre santé!
Toochka
20

J'ai personnalisé une ligne de bord qui prend en charge la ligne de tiret horizontale et verticale. code ci-dessous:

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
la source
Cette approche est-elle préférable à la forme xml?
IgorGanapolsky
parfait! ce que je cherchais
Emploi M
9

En utilisant cette classe, vous pouvez appliquer un effet "en pointillés et souligné" au texte sur plusieurs lignes. pour utiliser DashPathEffect, vous devez désactiver hardwareAccelerated de votre TextView (bien que la méthode DashPathEffect ait un problème avec le texte long). vous pouvez trouver mon exemple de projet ici: 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);
        }
    }
}

Résultat:

soulignement en pointillés

Nguyen Quoc Dat
la source
8

Si vous cherchez une ligne verticale, utilisez ce dessinable.

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

Les valeurs négatives en haut en bas et à gauche suppriment les côtés indésirables de la forme, laissant une seule ligne pointillée.

Utilisez-le dans une vue comme celle-ci.

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

J'ai utilisé ce qui suit comme arrière-plan pour la mise en page:

<?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
la source
Pourquoi android:shape="rectangle"au lieu de la ligne?
IgorGanapolsky
4

J'ai créé une ligne pointillée en pointillés pour EditText. Voici. Créez votre nouveau xml. par exemple dashed_border.xml Code ici:

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

Et utilisez votre nouveau fichier xml dans votre EditText par exemple:

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

À votre santé! :)

Wiktor Kalinowski
la source
3

Meilleure solution pour un fond pointillé fonctionnant parfaitement

<?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
la source
3

Pour un effet pointillé sur un canevas, définissez cet attribut sur l'objet de peinture:

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

Et modifiez la valeur 30 selon votre rendu: il représente la "distance" entre chaque point.

entrez la description de l'image ici

Arnaud
la source
2

La seule chose qui a fonctionné pour moi et je pense que c'est la manière la plus simple d'utiliser un chemin avec un objet de peinture comme celui-ci:

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

Puis onDraw (): (réinitialisation importante des appels si vous changez ces points entre les appels en attente, car Path enregistre tous les mouvements)

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

J'ai aimé la solution de Ruidge , mais j'avais besoin de plus de contrôle à partir de XML. Je l'ai donc changé en Kotlin et ajouté des attributs.

1) Copiez 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) Créez un fichier attr dans le répertoire / res et ajoutez-le

 <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) Ajoutez un style au fichier de styles

 <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) Vous pouvez maintenant utiliser le style par défaut

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

ou définir des attributs en 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
la source
2

Aucune de ces réponses n'a fonctionné pour moi. La plupart de ces réponses vous donnent une bordure semi-transparente. Pour éviter cela, vous devez envelopper à nouveau votre contenant avec un autre contenant de votre couleur préférée. Voici un exemple:

Voilà à quoi ça ressemble

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
la source
1

Je ne sais pas pourquoi mais les réponses votées ne fonctionnent pas pour moi. Je l'écris de cette façon et fonctionne bien.
Définissez une vue personnalisée:

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

Ensuite, vous pouvez l'utiliser dans votre xml:

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

J'ai créé une bibliothèque avec une vue personnalisée pour résoudre ce problème, et elle devrait être très simple à utiliser. Voir https://github.com/Comcast/DahDit pour plus. Vous pouvez ajouter des lignes en pointillés comme ceci:

<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
la source
Merci d'avoir partagé. Je vais devoir l'affiner pour mon cas d'utilisation, mais c'est exactement ce dont j'avais besoin pour commencer avec les vues personnalisées. À votre santé.
0

Similaire à tier777, voici une solution pour une ligne horizontale:

<?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'indice est <item android:top="-1dp">.

Afin d'afficher la ligne pointillée sur les anciens appareils (<= API 21), vous devez créer une vue avec android:layerType="software"(voir Bug potentiel ICS sur la ligne pointillée 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"
    />

Vous pouvez également ajouter la même vue sans android:layerType="software"pour layout-v23de meilleures performances, mais je ne suis pas sûr que cela fonctionnera sur tous les appareils avec API 23.

CoolMind
la source