437

I have a TextView and I'd like to add a black border along its top and bottom borders. I tried adding android:drawableTop and android:drawableBottom to the TextView, but that only caused the entire view to become black.

<TextView
    android:background="@android:color/green"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:drawableTop="@android:color/black"
    android:drawableBottom="@android:color/black"
    android:text="la la la" />

Is there a way to easily add a top and bottom border to a View (in particular, a TextView) in Android?

3
  • 2
    It's surprising nobody has mentioned dividerVertical ! This is the thing created by Android, to achieve, well, vertical dividers. COoldn't be easier and you do everything in the "Design" WYSIWYG panel in Android Studio.
    – Fattie
    Jun 26, 2014 at 10:52
  • note dividerVertical was implemented in API 11.
    – JPM
    Feb 26, 2015 at 18:04
  • 3
    Maybe you can show how to use dividerVertical?
    – androidguy
    Feb 24, 2017 at 1:50

25 Answers 25

458

In android 2.2 you could do the following.

Create an xml drawable such as /res/drawable/textlines.xml and assign this as a TextView's background property.

<TextView
android:text="My text with lines above and below"
android:background="@drawable/textlines"
/>

/res/drawable/textlines.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
      <shape 
        android:shape="rectangle">
            <stroke android:width="1dp" android:color="#FF000000" />
            <solid android:color="#FFDDDDDD" />

        </shape>
   </item>

   <item android:top="1dp" android:bottom="1dp"> 
      <shape 
        android:shape="rectangle">
            <stroke android:width="1dp" android:color="#FFDDDDDD" />
            <solid android:color="#00000000" />
        </shape>
   </item>

</layer-list>

The down side to this is that you have to specify an opaque background colour, as transparencies won't work. (At least i thought they did but i was mistaken). In the above example you can see that the solid colour of the first shape #FFdddddd is copied in the 2nd shapes stroke colour.

9
  • 11
    Also see this solution, which also works for TextViews, if you want a border all around: stackoverflow.com/questions/3263611/…
    – emmby
    Dec 9, 2010 at 20:09
  • 26
    Try using android:color="@null" to avoid opaque background problem. Jul 27, 2011 at 11:51
  • @emmby : when testing this code on tablet , it takes time to render on screen, after 1 sec borders get displayed when I scroll
    – Chetan
    Apr 3, 2012 at 11:40
  • 5
    The android:color="@null" trick didn't do the trick for me for keeping transparency and just displaying a border at one side of the view. Answer from user1051892 below did the job! Jul 12, 2013 at 8:57
  • 11
    This solution made a border on the left and right as well - though a thinner one. Jul 30, 2013 at 14:31
315

I've used a trick so that the border is displayed outside the container. With this trick only a line is drawn so the background will be shown of the underlying view.

<?xml version="1.0" encoding="utf-8"?>
<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="1dp"
                android:color="#FF000000" />

            <solid android:color="#00FFFFFF" />

            <padding android:left="10dp"
                android:right="10dp"
                android:top="10dp"
                android:bottom="10dp" />
        </shape>
    </item>

</layer-list>
10
  • 3
    This worked great for me, with a few tweaks to make the line a bit thinner.
    – Jeff
    Apr 19, 2013 at 18:30
  • 2
    Very nice trick, although it could be nicer if we don't have to trick the computer in order to get things done.
    – Max
    May 17, 2013 at 2:56
  • nicely done! what you should watch is item's left, top, right, bottom should -(stroke's width)dp
    – asakura89
    Jun 10, 2013 at 2:55
  • Didn't show any border - just made my view content look smaller :( Jul 30, 2013 at 14:41
  • 1
    Nicely done, worked with transparent background. Tested in 2.2 and 4.4.2. Should cover all in between :)
    – HumaN
    Dec 27, 2013 at 3:46
121

To add a 1dp white border at the bottom only and to have a transparent background you can use the following which is simpler than most answers here.

For the TextView or other view add:

android:background="@drawable/borderbottom"

And in the drawable directory add the following XML, called borderbottom.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:top="-2dp" android:left="-2dp" android:right="-2dp">
        <shape android:shape="rectangle">
            <stroke android:width="1dp" android:color="#ffffffff" />
            <solid android:color="#00000000" />
        </shape>
    </item>
</layer-list>

If you want a border at the top, change the android:top="-2dp" to android:bottom="-2dp"

The colour does not need to be white and the background does not need to be transparent either.

The solid element may not be required. This will depend on your design (thanks V. Kalyuzhnyu).

Basically, this XML will create a border using the rectangle shape, but then pushes the top, right and left sides beyond the render area for the shape. This leaves just the bottom border visible.

6
  • 9
    This is the best solution, as it does not create overdraw like the others
    – Greg Ennis
    Jan 6, 2016 at 15:00
  • Is there a reason that negative positions are twice as big as stroke with (-2dp vs 1dp)? Seems to work when they are equal in amount (-1 and 1). Aug 18, 2016 at 10:53
  • @DenisKniazhev : When using -2dp the result was always clean. I think there was test case where the result was not clean. I can't remember if it was a low or high density screen or even an older version of Android (2.x maybe).
    – Tigger
    Aug 18, 2016 at 11:22
  • Interesting. Do you know if this is a general case, for example if I use 4dp for stroke width should I use -8dp for positioning? Aug 18, 2016 at 12:46
  • 1
    @DenisKniazhev : (from memory) it looked like a floating point calculation that was just a little to big or small. This means a value of -5dp would be all that is needed with a width value of 4pd. It simply needed to be a little bigger to get over the float value inaccuracy.
    – Tigger
    Aug 19, 2016 at 12:09
102

Option 1: Shape Drawable

This is the simplest option if you want a border around a layout or view in which you can set the background. Create an XML file in the drawable folder that looks something like this:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="#8fff93" />

    <stroke
        android:width="1px"
        android:color="#000" />

</shape>

You can remove the solid if you don't want a fill. The set background="@drawable/your_shape_drawable" on your layout/view.

Option 2: Background View

Here's a little trick I've used in a RelativeLayout. Basically you have a black square under the view you want to give a border, and then give that view some padding (not margin!) so the black square shows through at the edges.

Obviously this only works properly if the view doesn't have any transparent areas. If it does I would recommend you write a custom BorderView which only draws the border - it should only be a few dozen lines of code.

<View
    android:id="@+id/border"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@+id/image"
    android:layout_alignLeft="@+id/image"
    android:layout_alignRight="@+id/image"
    android:layout_alignTop="@+id/main_image"
    android:background="#000" />

<ImageView
    android:id="@+id/image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_...
    android:padding="1px"
    android:src="@drawable/..." />

If you're wondering, it does work with adjustViewBounds=true. However, it doesn't work if you want to have a background in an entire RelativeLayout, because there is a bug that stops you filling a RelativeLayout with a View. In that case I'd recommend the Shape drawable.

Option 3: 9-patch

A final option is to use a 9-patch drawable like this one:

You can use it on any view where you can set android:background="@drawable/...". And yes it does need to be 6x6 - I tried 5x5 and it didn't work.

The disadvantage of this method is you can't change the colours very easily, but if you want fancy borders (e.g. only a border at the top and bottom, as in this question) then you may not be able to do them with the Shape drawable, which isn't very powerful.

Option 4: Extra views

I forgot to mention this really simple option if you only want borders above and below your view. You can put your view in a vertical LinearLayout (if it isn't already) and then add empty Views above and below it like this:

<View android:background="#000" android:layout_width="match_parent" android:layout_height="1px"/>
7
  • 4
    9 patch and the shape drawable are ok, but i would recommend against adding views or imageviews to solve such a problem. The reason being is that you should be removing as many such <elements> from your layouts to improve layout redrawing and animation. I would strip these out right away and implement some similar to option 1 or 2.
    – Emile
    Nov 6, 2012 at 19:55
  • 2
    @Emile That's true, but if you're using a custom ListView that doesn't support dividers a simple View is fine. The performance impact is next to nil, especially if you're sure to keep your layout depth down. It also circumvents bugs with ListView dividers across devices (I've seen some devices that ignore this property).
    – Tom
    Jan 14, 2013 at 19:56
  • You can also use the efficient viewholder pattern with listviews to ensure you reduce the number of calls to findViewByID which is often the cause of poor list performance.
    – Emile
    Jan 15, 2013 at 16:55
  • In iOS you have only one way to do that. On android you should test at least four, in my case option 4 was the way to go. Sometimes drawables as background hang to render, be aware of it. Oct 22, 2013 at 16:55
  • 1
    Why android didn't have the easiest solution for such things? as in other language, like HTML, CSS, or something JavaFX, WPF...... Apr 13, 2017 at 17:04
39

The currently accepted answer doesn't work. It creates thin vertical borders on the left and right sides of the view as a result of anti-aliasing.

This version works perfectly. It also allows you to set the border widths independently, and you can also add borders on the left / right sides if you want. The only drawback is that it does NOT support transparency.

Create an xml drawable named /res/drawable/top_bottom_borders.xml with the code below and assign it as a TextView's background property.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#DDDD00" /> <!-- border color -->
        </shape>
    </item>

    <item
        android:bottom="1dp" 
        android:top="1dp">   <!-- adjust borders width here -->
        <shape android:shape="rectangle">
            <solid android:color="#FFFFFF" />  <!-- background color -->
        </shape>
    </item>
</layer-list>

Tested on Android KitKat through Marshmallow

2
  • How to make inside transparent ? Jul 12, 2016 at 2:16
  • 1
    @HiteshSahu I think the downside of this is that you would have to match the background of the layout with the background of the widget here
    – chntgomez
    Jul 19, 2016 at 16:34
36

So I wanted to do something slightly different: a border on the bottom ONLY, to simulate a ListView divider. I modified Piet Delport's answer and got this:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
   <item>
      <shape 
        android:shape="rectangle">
            <solid android:color="@color/background_trans_light" />    

        </shape>
   </item>

    <!-- this mess is what we have to do to get a bottom border only. -->
   <item android:top="-2dp"
         android:left="-2dp"
         android:right="-2dp"
         android:bottom="1px"> 
      <shape 
        android:shape="rectangle">    
            <stroke android:width="1dp" android:color="@color/background_trans_mid" />
            <solid android:color="@null" />
        </shape>
   </item>

</layer-list>

Note using px instead of dp to get exactly 1 pixel divider (some phone DPIs will make a 1dp line disappear).

4
  • 2
    dear! what is the value of "@color/background_trans_light"? Aug 8, 2013 at 9:24
  • Cheers @phreakhead, this actually works for me! No top, left, or right border. Exactly what I needed, thanks!
    – shanehoban
    Apr 29, 2014 at 10:25
  • 3
    Please can you explain why when you put -2dp it dissapears and when you put -1dp it is still visible? Thanks! Aug 26, 2015 at 11:31
  • @phreakhead better if you add some explanation to this
    – Maveňツ
    Aug 7, 2020 at 8:16
12

Add file to res/drawable

<?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:left="-2dp" android:right="-2dp">
            <shape android:shape="rectangle">
                <stroke
                    android:width="1dp"
                    android:color="#000000" />
            </shape>
        </item>
    </layer-list>

Add link on this file to background property

9

Just as @Nic Hubbard said, there is a very easy way to add a border line.

<View
    android:layout_width="match_parent"
    android:layout_height="2dp"
    android:background="#000000" >
</View>

You can change the height and background color to whatever you want.

8

You can also wrap the view in a FrameLayout, then set the frame's background color and padding to what you want; however, the textview, by default has a 'transparent' background, so you'd need to change the textview's background color too.

1
  • Pretty simple. You control the size and direction of outlines by the margins of the inner View. Thanks.
    – SMBiggs
    Apr 20, 2017 at 23:19
8

My answers is based on @Emile version but I use transparent color instead of solid.
This example will draw a 2dp bottom border.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape android:shape="rectangle" >
            <stroke  android:width="2dp"
                     android:color="#50C0E9" />
            <solid android:color="@android:color/transparent" />
        </shape>
    </item>
    <item  android:bottom="2dp" >
        <shape android:shape="rectangle" >
            <stroke  android:width="2dp"
                     android:color="@color/bgcolor" />
            <solid android:color="@android:color/transparent" />
        </shape>
    </item>
</layer-list>

@color/bgcolor is the color of the background on wich you draw your view with border.

If you want to change the position of the border change the offset with one of:

android:bottom="2dp"
android:top="2dp"
android:right="2dp"
android:left="2dp"

or combine them to have 2 or more borders:

android:bottom="2dp" android:top="2dp"
0
6

Simplest way to add borders to inset the borders using InsetDrawable,following will show top border only :

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetBottom="-2dp"
    android:insetLeft="-2dp"
    android:insetRight="-2dp">
    <shape android:shape="rectangle">

        <solid android:color="@color/light_gray" />
        <stroke
            android:width=".5dp"
            android:color="@color/dark_gray" />
    </shape>
</inset>
6

You can do this by this code snippet -

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--Minus (-) how much dp you gave in the stroke width from left right-->
    <item android:left="-10dp" android:right="-10dp">
        <shape
            android:shape="rectangle">
            <stroke android:width="10dp" android:color="@android:color/holo_red_dark" />
           <!--This is the main background -->
            <solid android:color="#FFDDDDDD" />
        </shape>
    </item>
</layer-list>

Preview -

enter image description here

5

Why not just create a 1dp high view with a background color? Then it can be easily placed where you want.

5

To change this:

<TextView
    android:text="My text"
    android:background="@drawable/top_bottom_border"/>

I prefer this approach in "drawable/top_bottom_border.xml":

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <gradient
                android:angle="270"
                android:startColor="#000"
                android:centerColor="@android:color/transparent"
                android:centerX="0.01" />
        </shape>
    </item>
    <item>
        <shape>
            <gradient
                android:angle="90"
                android:startColor="#000"
                android:centerColor="@android:color/transparent"
                android:centerX="0.01" />
        </shape>
    </item>
</layer-list>

This only makes the borders, not a rectangle that will appear if your background has a color.

4

Just to add my solution to the list..

I wanted a semi transparent bottom border that extends past the original shape (So the semi-transparent border was outside the parent rectangle).

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
  <item>
    <shape android:shape="rectangle" >      
      <solid android:color="#33000000" /> <!-- Border colour -->
    </shape>
  </item>
  <item  android:bottom="2dp" >
    <shape android:shape="rectangle" >     
      <solid android:color="#164586" />
    </shape>
  </item>
</layer-list>

Which gives me;

enter image description here

4

First make a xml file with contents shown below and name it border.xml and place it inside the layout folder inside the res directory

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke android:width="1dp" android:color="#0000" />
    <padding android:left="0dp" android:top="1dp" android:right="0dp"
        android:bottom="1dp" />
</shape>

After that inside the code use

TextView tv = (TextView)findElementById(R.id.yourTextView);
tv.setBackgroundResource(R.layout.border);

This will make a black line on top and bottom of the TextView.

3
  • Yes, It will Work, I have checked. Button button= (Button) findViewById(R.id.button); button.setBackgroundResource(R.layout.border); May 21, 2012 at 9:09
  • I have used black color in the above xml file, your background color might be black, try by using some other color. It will definitely work <?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="schemas.android.com/apk/res/android"> <solid android:color="#474848" /> <stroke android:width="1dp" android:color="#ffff00" /> <padding android:left="1dp" android:top="1dp" android:right="1dp" android:bottom="1dp" /> </shape> May 21, 2012 at 9:50
  • 1
    Didn't work for me. The border line was painted in the middle of the text view - horizontally. Jul 30, 2013 at 12:34
4

Simply add Views at the top and bottom of the View

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/your_color"
        app:layout_constraintBottom_toTopOf="@+id/textView"
        app:layout_constraintEnd_toEndOf="@+id/textView"
        app:layout_constraintStart_toStartOf="@+id/textView" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:gravity="center"
        android:text="Testing"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/your_color"
        app:layout_constraintEnd_toEndOf="@+id/textView"
        app:layout_constraintStart_toStartOf="@+id/textView"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

</android.support.constraint.ConstraintLayout>
3

Write down below code

<View
    android:layout_width="wrap_content"
    android:layout_height="2dip"
    android:layout_below="@+id/topics_text"
    android:layout_marginTop="7dp"
    android:layout_margin="10dp"
    android:background="#ffffff" />
0
1

Try wrapping the image with a linearlayout, and set it's background to the border color you want around the text. Then set the padding on the textview to be the thickness you want for your border.

1

You can also use a 9-path to do your job. Create it so that colored pixel do not multiply in height but only the transparent pixel.

1

Based on accepted answer of Pi Delport and Emile, I made it a little simpler

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>  <!--divider TOP and BOTTOM-->
    <shape android:shape="rectangle">
        <stroke 
            android:width="1dp"
            android:color="@color/divider" />
    </shape>
</item>

<!--background surface-->
<item
    android:top="1dp"
    android:bottom="1dp">
    <shape android:shape="rectangle">
        <solid android:color="@color/background" />
    </shape>
</item>
0
// Just simply add border around the image view or view

<ImageView
                android:id="@+id/imageView2"
                android:layout_width="90dp"
                android:layout_height="70dp"
                android:layout_centerVertical="true"
                android:layout_marginRight="10dp"
                android:layout_toLeftOf="@+id/imageView1"
                android:background="@android:color/white"
                android:padding="5dip" />

// After that dynamically put color into your view or image view object

objView.setBackgroundColor(Color.GREEN);

//VinodJ/Abhishek
0
<shape xmlns:android="http://schemas.android.com/apk/res/android">

<solid android:color="@color/light_grey1" />
<stroke
    android:width="1dip"
    android:color="@color/light_grey1" />

<corners
    android:bottomLeftRadius="0dp"
    android:bottomRightRadius="0dp"
    android:topLeftRadius="5dp"
    android:topRightRadius="5dp" />

    </shape>
-1
<TextView
    android:id="@+id/textView3"
    android:layout_width="match_parent"
    android:layout_height="2dp"
    android:background="#72cdf4"
    android:text=" aa" />

Just Add this TextView below the text where you want to add the border

-1

Just to enforce @phreakhead ´s and user1051892 ´s answers, <item android:bottom|android:left|android:right|android:top> if negative, must to be greater than <stroke android:width>. If not, item´s painting will be mixed with stroke´s painting and you may think these values are not working.

Not the answer you're looking for? Browse other questions tagged or ask your own question.