【问题标题】:How do I make a dotted/dashed line in Android?如何在 Android 中制作虚线/虚线?
【发布时间】:2011-05-23 22:23:59
【问题描述】:

我正在尝试画一条虚线。我现在正在使用它作为实线:

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

我需要这样的东西,但点而不是实心。我想避免在透明布局和实体布局之间交替使用数百个布局。

【问题讨论】:

    标签: android


    【解决方案1】:

    没有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="#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" />
    

    效果:

    【讨论】:

    • 我不明白为什么我的手机上没有空白的线路,而我在 Eclipse 中看到图形布局中的空白。
    • 没关系,我在这里找到了解决方案:stackoverflow.com/questions/10843402/… 只需将图层类型设置为软件:android:layerType="software"
    • 使用canvas.drawLine()时有一个known bug。作为禁用硬件加速的替代方法,您可以改用canvas.drawPath
    • 使用dp 而不是px
    • 已验证这适用于 Android 6.0.1 和 4.4.4。有两点需要注意:1)你确实需要一个ImageView,一个以drawable为背景的View没有这样做; 2) android:layerType="software" 必须在 ImageView 上设置。
    【解决方案2】:

    在绘制对象上设置路径效果

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

    您可以通过在 int[] 数组中提供更多数字来创建各种点状图案,它指定了破折号和间隙的比率。这是一条简单的同样虚线。

    【讨论】:

    • 我直接复制粘贴了这段代码,但什么也没发生。我应该编写额外的代码来让它工作吗?
    • 我要申请多种颜色。还有其他解决方案吗?
    【解决方案3】:

    使用 XML 创建虚线。
    在 drawable 文件夹中创建 xml 并将该背景赋予要设置虚线边框的项目。

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

    为项目添加背景:

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

    【讨论】:

    • 如果您需要圆角半径,只需将&lt;corners android:radius="5dp" /&gt; 添加到您的形状。请参阅stackoverflow.com/a/41940609/1000551 了解更多信息
    • 我认为图层列表对于单个项目来说是不必要的。我使用 作为根元素,它的工作原理是一样的。
    【解决方案4】:

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

    设置为视图的背景:

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

    【讨论】:

    • 你能解释一下吗?
    • 谢谢,线索是&lt;item android:bottom="-1dp" android:left="-1dp" android:right="-1dp" &gt;,如果你想要水平线1dp粗细。
    • 太棒了。对我来说几乎是开箱即用的。我需要的唯一更改是更改笔画标记; 2dp 宽度和 4dp dashGap。
    • 对于 API android:layerType="software" 添加到视图中或写入view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)(请参阅stackoverflow.com/questions/10843402/…)。
    【解决方案5】:

    当我想画虚线时,我所做的是定义一个可绘制的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>
    

    然后在布局中定义一个背景为 dash_line 的视图。注意要包含android:layerType="software",否则不起作用。

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

    【讨论】:

      【解决方案6】:

      我自定义了一个支持水平和垂直虚线的虚线。代码如下:

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

      【讨论】:

      • 这种方法比 xml 形状更可取吗?
      【解决方案7】:

      如果您正在寻找一条垂直线,请使用此可绘制对象。

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

      负的 top bottom 和 left 值删除了形状不需要的边,留下一条虚线。

      在这样的视图中使用它。

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

      【讨论】:

        【解决方案8】:

        通过使用此类,您可以将“虚线和下划线”效果应用于多行文本。要使用 DashPathEffect,您必须关闭 TextView 的 hardwareAccelerated(尽管 DashPathEffect 方法存在长文本问题)。你可以在这里找到我的示例项目: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);
                }
            }
        }
        

        结果:

        【讨论】:

          【解决方案9】:

          对于画布上的虚线效果,将此属性设置为绘画对象:

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

          并根据您的渲染情况更改值 30:它代表每个点之间的“距离”。

          【讨论】:

            【解决方案10】:

            我使用以下作为布局的背景:

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

            【讨论】:

            • 为什么是android:shape="rectangle" 而不是line?
            【解决方案11】:

            我为 EditText 创建了点划线。干得好。 创建新的 xml。例如 dashed_border.xml 这里的代码:

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

            并在 EditText 中使用新的 xml 文件,例如:

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

            干杯! :)

            【讨论】:

              【解决方案12】:

              使用 ShapeDrawable 代替 LinearLayout 并使用 dashWidth 和 dashGap

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

              【讨论】:

                【解决方案13】:

                完美运行虚线背景的最佳解决方案

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

                【讨论】:

                  【解决方案14】:

                  我喜欢Ruidge 的解决方案,但我需要更多来自 XML 的控制。所以我把它改成了 Kotlin 并添加了属性。

                  1) 复制 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) 在 /res 目录下创建一个 attr 文件并添加这个

                   <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) 将样式添加到 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) 现在可以使用默认样式了

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

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

                  【讨论】:

                    【解决方案15】:

                    这些答案都不适合我。这些答案中的大多数都给你一个半透明的边框。为避免这种情况,您需要用另一个具有您喜欢的颜色的容器再次包裹您的容器。这是一个例子:

                    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>
                    

                    【讨论】:

                      【解决方案16】:

                      唯一对我有用并且我认为这是最简单的方法是使用带有这样的绘画对象的路径:

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

                      然后 onDraw():(如果你在 ondraw 调用之间更改这些点,重要的调用重置,导致 Path 保存所有动作)

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

                      【讨论】:

                        【解决方案17】:

                        我不知道为什么,但投票的答案对我不起作用。我这样写,效果很好。
                        定义自定义视图:

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

                        然后你可以在你的xml中使用它:

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

                        【讨论】:

                          【解决方案18】:

                          我创建了一个带有自定义视图的库来解决这个问题,它应该非常易于使用。有关更多信息,请参阅https://github.com/Comcast/DahDit。您可以像这样添加虚线:

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

                          【讨论】:

                          • 感谢分享。我将不得不针对我的用例对其进行改进,但这正是我开始使用自定义视图所需要的。干杯。
                          【解决方案19】:

                          类似于tier777,这里有一个水平线的解决方案:

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

                          线索是&lt;item android:top="-1dp"&gt;

                          为了在旧设备 (android:layerType="software" 创建一个视图(请参阅 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"
                              />
                          

                          您还可以将不带android:layerType="software" 的相同视图添加到layout-v23 以获得更好的性能,但我不确定它是否适用于所有具有API 23 的设备。

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 2011-05-06
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2016-03-11
                            • 2018-10-19
                            • 1970-01-01
                            相关资源
                            最近更新 更多