Wie mache ich in Android eine gepunktete / gestrichelte Linie?

254

Ich versuche eine gepunktete Linie zu machen. Ich verwende dies gerade für eine durchgezogene Linie:

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

Ich brauche so etwas, aber gepunktet statt fest. Ich möchte vermeiden, dass Hunderte von Layouts zwischen einem transparenten und einem soliden Layout wechseln.

Jason Robinson
quelle

Antworten:

515

Ohne 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="#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
quelle
21
Ich verstehe nicht, warum ich eine Leitung ohne Lücken auf meinem Telefon bekomme, während ich die Lücken im grafischen Layout in Eclipse sehe.
Dante
73
Egal , ich habe die Lösung hier gefunden: stackoverflow.com/questions/10843402/… Setzen Sie einfach den Layertyp auf software: android: layerType = "software"
Dante
7
Bei der Verwendung ist ein Fehler bekanntcanvas.drawLine() . Alternativ zum Deaktivieren der Hardwarebeschleunigung können Sie canvas.drawPathstattdessen verwenden.
Hgoebl
10
verwenden dp statt px .
S.M_Emamian
7
Verifiziert, dass dies sowohl unter Android 6.0.1 als auch unter 4.4.4 funktioniert. Zwei Dinge zu beachten: 1) Sie benötigen in der Tat eine ImageView, eine Ansicht mit dem Zeichen als Hintergrund hat dies nicht getan; 2) android:layerType="software"muss in der ImageView eingestellt sein.
Jonik
206

Der Pfadeffekt wird auf das Malobjekt eingestellt

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

Sie können alle Arten von gepunkteten Mustern erstellen, indem Sie mehr Zahlen in das Array int [] eingeben, in dem die Verhältnisse von Strich und Lücke angegeben sind. Dies ist eine einfache, gleichermaßen gestrichelte Linie.

silikoneagle
quelle
warum tut das jetzt für mich? stackoverflow.com/questions/12401311/…
Chris.Zou
versuchen Sie neue float [] {5,10,15,20} im Konstruktor
siliconeagle
4
Ich bin etwas neu in der Android-Entwicklung. Ich möchte fragen, wie das Malobjekt mit gestricheltem Effekt zu dem soeben erstellten linearen Layout hinzugefügt wird.
DirkJan
Ich habe diesen Code direkt kopiert und eingefügt, aber es ist nichts passiert. Sollte ich zusätzlichen Code schreiben, damit es funktioniert?
Jason
50

Gepunktete Linie mit XML erstellen.
Erstellen Sie XML in einem zeichnbaren Ordner und geben Sie den Hintergrund für das Element an, für das Sie einen gepunkteten Rand festlegen möchten.

XML-Hintergrund erstellen "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>

Hinzufügen dieses Hintergrunds zum Element:

<Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/dashed_border"/>
Sargam
quelle
Wenn Sie einen Radius für Ecken benötigen, fügen <corners android:radius="5dp" />Sie ihn einfach Ihrer Form hinzu. Siehe stackoverflow.com/a/41940609/1000551 für weitere Informationen
Vadim Kotov
Ich denke, die Ebenenliste ist für ein einzelnes Element nicht erforderlich. Ich habe die <Form> als Stammelement verwendet und es funktioniert genauso.
big_m
37

XML erstellen (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>

Als Hintergrund Ihrer Ansicht festlegen:

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@drawable/view_line_dotted" />
tier777
quelle
Kannst du es bitte erklären?
Skywall
1
Vielen Dank, der Hinweis ist <item android:bottom="-1dp" android:left="-1dp" android:right="-1dp" >, wenn Sie eine horizontale Linie 1dp Dicke wollen.
CoolMind
Genial. Funktioniert für mich fast sofort. Die einzige Änderung, die ich brauchte, war das Ändern des Strich-Tags. 2dp width und 4dp dashGap.
Sufian
Für Geräte mit API <21 android:layerType="software"in eine Ansicht hinzufügen oder schreiben view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)(siehe stackoverflow.com/questions/10843402/… ).
CoolMind
24

Als ich eine gepunktete Linie zeichnen wollte, definierte ich eine zeichnbare 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:dashGap="3dp"
    android:dashWidth="2dp"
    android:width="1dp"
    android:color="@color/black" />
</shape>

Und dann definieren Sie im Layout einfach eine Ansicht mit Hintergrund als dash_line . Hinweis für Android: layerType = "Software" , sonst funktioniert es nicht.

<View
            android:layout_width="match_parent"
            android:layout_height="5dp"
            android:background="@drawable/dash_line"
            android:layerType="software" />
Tony Vu
quelle
Danke Kumpel! Das android:layerType="software"ist das, wonach ich gesucht habe! Prost!
Toochka
20

Ich habe eine Strichlinie benutzerdefiniert, die horizontale und verikale Strichlinie unterstützt. Code unten:

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
quelle
Ist dieser Ansatz der XML-Form vorzuziehen?
IgorGanapolsky
perfekt! was ich gesucht habe
Job M
9

Mit dieser Klasse können Sie den Effekt "gestrichelt und unterstrichen" auf Text mit mehreren Zeilen anwenden. Um DashPathEffect verwenden zu können, müssen Sie hardwareAccelerated Ihrer TextView deaktivieren (obwohl die DashPathEffect-Methode ein Problem mit Langtext hat). Mein Beispielprojekt finden Sie hier: 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);
        }
    }
}

Ergebnis:

gestrichelt unterstrichen

Nguyen Quoc Dat
quelle
8

Wenn Sie nach einer vertikalen Linie suchen, verwenden Sie diese Zeichenfunktion.

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

Die negativen Werte oben unten und links entfernen die unerwünschten Seiten der Form und hinterlassen eine einzelne gestrichelte Linie.

Verwenden Sie es in einer Ansicht wie dieser.

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

Ich habe das Folgende als Hintergrund für das Layout verwendet:

<?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
quelle
Warum android:shape="rectangle"statt Linie?
IgorGanapolsky
4

Ich habe eine gestrichelte gepunktete Linie für EditText erstellt. Bitte schön. Erstellen Sie Ihre neue XML. zB dashed_border.xml Code hier:

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

Und verwenden Sie Ihre neue XML-Datei in Ihrem EditText zum Beispiel:

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

Prost! :) :)

Wiktor Kalinowski
quelle
3

Beste Lösung für gepunkteten Hintergrund funktioniert perfekt

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

Legen Sie für einen gepunkteten Effekt auf einer Leinwand dieses Attribut auf das Malobjekt fest:

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

Ändern Sie den Wert 30 nach Ihren Wünschen: Er repräsentiert den "Abstand" zwischen den einzelnen Punkten.

Geben Sie hier die Bildbeschreibung ein

Arnaud
quelle
2

Das einzige, was für mich funktioniert hat und ich denke, es ist der einfachste Weg, einen Pfad mit einem Malobjekt wie diesem zu verwenden:

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

Dann onDraw (): (Wichtiger Anruf wird zurückgesetzt, wenn Sie diese Punkte zwischen Ondraw-Aufrufen ändern, da Path alle Bewegungen speichert.)

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

Ich mochte die Lösung von Ruidge , aber ich brauchte mehr Kontrolle über XML. Also habe ich es in Kotlin geändert und Attribute hinzugefügt.

1) Kopieren Sie die Kotlin-Klasse:

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) Erstellen Sie eine attr- Datei im Verzeichnis / res und fügen Sie diese hinzu

 <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) In einen Stil der Stile - Datei

 <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) Jetzt können Sie den Standardstil verwenden

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

oder Attribute in XML festlegen

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

Keine dieser Antworten hat bei mir funktioniert. Die meisten dieser Antworten geben Ihnen einen halbtransparenten Rand. Um dies zu vermeiden, müssen Sie Ihren Behälter erneut mit einem anderen Behälter mit Ihrer bevorzugten Farbe umwickeln. Hier ist ein Beispiel:

So sieht es aus

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

Ich weiß nicht warum, aber die abgestimmten Antworten funktionieren bei mir nicht. Ich schreibe es so und funktioniert gut.
Definieren Sie eine benutzerdefinierte Ansicht:

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

Dann können Sie es in Ihrer XML verwenden:

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

Ich habe eine Bibliothek mit einer benutzerdefinierten Ansicht erstellt, um dieses Problem zu lösen, und sie sollte sehr einfach zu verwenden sein. Weitere Informationen finden Sie unter https://github.com/Comcast/DahDit . Sie können gestrichelte Linien wie folgt hinzufügen:

<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
quelle
Danke für das Teilen. Ich werde es für meinen Anwendungsfall verfeinern müssen, aber genau das war es, was ich brauchte, um mit benutzerdefinierten Ansichten zu beginnen. Prost.
0

Ähnlich wie bei Tier777 gibt es hier eine Lösung für eine horizontale Linie:

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

Der Hinweis ist <item android:top="-1dp">.

Um auf alten Geräten gestrichelte Linien anzuzeigen (<= API 21), sollten Sie eine Ansicht erstellen mit android:layerType="software"(siehe Android-gestrichelter potenzieller ICS-Fehler mit gestrichelten Linien ):

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

Sie können dieselbe Ansicht auch ohne hinzufügen android:layerType="software", layout-v23um eine bessere Leistung zu erzielen. Ich bin jedoch nicht sicher, ob sie auf allen Geräten mit API 23 funktioniert.

CoolMind
quelle