Open-sided Android stroke?

59,132

Solution 1

I achieved a good solution with this one:

<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is the line -->
    <item android:top="-1dp" android:right="-1dp" android:left="-1dp">
      <shape>
            <solid android:color="@android:color/transparent" />
            <stroke android:width="1dp" android:color="#ffffff" />
      </shape>
    </item>

</layer-list>

This works well in case you need a transparent background but still an open stroke color (In my case I only needed a bottom line). If you need a background color you can add a solid shape color as in Maragues answer.

EDIT 1

Sometimes, for High Density devices, using low dip values may end in very thin or invisible strokes or distances. This may happen to you also when setting ListView dividers.

The simplest workaround is to use a distance of 1px instead of 1dp. This will make the line always visible at all densities. The best solution would be to create dimension resources for each density, to get the best size for each device.

Edit 2

Fun, but I tried to use this 6 years later and I can't get a good result on Lollipop devices.

Probably the current solution is to use 9-patch. Android should have made an easy solution for this problem after all this time.

Solution 2

I know this question was posted long ago, so the answer will not be used by the person who posted this question, but it may still help others.

 <?xml version="1.0" encoding="UTF-8"?>
    <!-- inset is used to remove border from top, it can remove border from any other side-->
    <inset xmlns:android="http://schemas.android.com/apk/res/android"
        android:insetTop="-2dp"
        >
    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rectangle">
        <stroke android:width="1dp" android:color="#b7b7b7" />
        <corners android:bottomRightRadius="5dp"  android:bottomLeftRadius="5dp"/>

        <solid android:color="#454444"/>
    </shape>
    </inset>

Use the inset tag and give a negative value for the side border you want to remove.

The possible values are:

android:insetTop="-1dp" android:insetBottom="-1dp" android:insetLeft="-1dp" android:insetRight="-1dp"

Solution 3

I solved this by using a list-layer, combining two shapes, one of which with height 1dp placed at the bottom

optionscreen_bottomrectangle.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is the line -->
<item>
      <shape>
            <solid android:color="#535353" />
      </shape>
</item>
<!-- This is the main color -->
<item android:bottom="1dp">
     <shape>
           <solid android:color="#252525" />
     </shape>
</item>
</layer-list>

Then, in the layout/main.xml file

<TextView
    android:id="@+id/bottom_rectangle"
    android:background="@drawable/optionscreen_bottomrectangle"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_below="@id/table_options"
    android:layout_above="@id/exit_bar"/>

Which fills the gap between table_options and exit_bar with a background and just before exit_bar prints a 1dp line. This did the trick for me, I hope it helps someone else.

Answer edited to place layers in the correct order. Thx Alex!

Solution 4

Another take on the other responses using padding instead. This little snipplet makes a border on top and bottom.

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- This is the line -->
    <item>
          <shape>
                <padding android:left="0dp" android:top="1dp" android:right="0dp" android:bottom="1dp"/>
                <solid android:color="#898989" />
          </shape>
    </item>
    <!-- This is the main color -->
    <item>
         <shape>
             <solid android:color="#ffffff" />
         </shape>
    </item>
</layer-list>

Solution 5

@Maragues's answer is backwards, as layer-list drawables draw from top to bottom (meaning the last item in the list is drawn on top):

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is the line -->
<item>
      <shape>
            <solid android:color="#535353" />
      </shape>
</item>
<!-- This is the main color -->
<item android:bottom="1dp">
     <shape>
           <solid android:color="#252525" />
     </shape>
</item>

</layer-list>

This will effectively fill the shape with the line color, then draw the background color on top of it, leaving the last 1dp clear for the line color to show through.

Share:
59,132

Related videos on Youtube

Reed Morse
Author by

Reed Morse

Updated on September 10, 2020

Comments

  • Reed Morse
    Reed Morse over 3 years

    Is it possible to create an Android shape object with stroke on only certain sides?

    Eg I have:

    <stroke 
     android:width="3dip" 
     android:color="#000000"
        android:dashWidth="10dip" 
        android:dashGap="6dip" />
    

    Which is similar to this CSS:

    border: 3px dashed black;
    

    How can I set the stroke on just one side? This is how I would do it in CSS:

    border-left: 3px dashed black;
    

    How do you do this in Android XML?

  • MrSnowflake
    MrSnowflake about 14 years
    It might be handy not to post an answer if you really want to have an answer yourself. When other devs see there's already an answer (altough in this case it's actually non) they are not as inclined to answer.
  • Edu Zamora
    Edu Zamora over 12 years
    This also worked for me, but I don't know exactly why I had to use -2dp instead of -1dp. If I used the latter, I still could see a thin line.
  • htafoya
    htafoya over 12 years
    @EduZamora yes it seems that for high density devices -1dp doesn't work as expected
  • Lumii
    Lumii almost 12 years
    I am also getting border for all sides, but not bottom only border.
  • htafoya
    htafoya almost 12 years
    @YanChengCHEOK try with 1px instead of 1dp.
  • abriggs
    abriggs almost 11 years
    @htafoya this is a brilliant solution. Thanks!
  • Jordy
    Jordy over 10 years
    I changed it to dip instead.
  • htafoya
    htafoya over 10 years
    @Jordy dip is the same than dp.
  • MacKinley Smith
    MacKinley Smith about 10 years
    This is by far the best answer if you need rounded corners.
  • Boy
    Boy about 10 years
    This one also helped me tremendously. Please give it a try and upvote
  • Lalit Sharma
    Lalit Sharma over 9 years
    @ug_ I think this is the best approach. Works perfectly, thanks
  • Admin
    Admin over 9 years
    @htafoya I am using it for my button..but it shows at top instead of bottom..can you help me with this?
  • Murat Ögat
    Murat Ögat over 9 years
    Works. Looks completely wrong in Android Studio (v1.1) preview pane but on the device it's fine.
  • Pointer Null
    Pointer Null about 6 years
    Artifacts are there likely due to OpenGL rounding/filtering, so I believe using doubled negative inset of stroke height should solve it. If stroke width is 2dp, set inset to -4dp.
  • Kiran
    Kiran almost 4 years
    Yeah and don't do what I did and try and put the inset attr in the stroke tag without reading the rest of the answer! (thanks for the answer BTW OP. Perfect solution)
  • Hao Qi
    Hao Qi almost 4 years
    elegant ! I love this solution