How do I create a ListView with rounded corners in Android?
-
This question is really useful,so is your answer..!! – Sajad Karuthedath Jan 22 '14 at 12:40
11 Answers
Here is one way of doing it (Thanks to Android Documentation though!):
Add the following into a file (say customshape.xml) and then place it in (res/drawable/customshape.xml)
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#SomeGradientBeginColor"
android:endColor="#SomeGradientEndColor"
android:angle="270"/>
<corners
android:bottomRightRadius="7dp"
android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp"
android:topRightRadius="7dp"/>
</shape>
Once you are done with creating this file, just set the background in one of the following ways:
Through Code:
listView.setBackgroundResource(R.drawable.customshape);
Through XML, just add the following attribute to the container (ex: LinearLayout or to any fields):
android:background="@drawable/customshape"
Hope someone finds it useful...
-
2Thanks for the great tip. Just FYI, copy-pasting gave me a runtime exception saying, "XmlPullParserException: Binary XML file line #4
tag requires 'angle' attribute to be a multiple of 45".. Easily remedied by changing the angle to 270. – allclaws Jan 25 '10 at 16:25 -
Thanks for the fix... But I don't know why that could be happening.. Did you find any specific reason? – Legend Jan 26 '10 at 17:21
-
Thanks for the tip! Just one problem though - I have created a roundedrectangle.xml but eclipse code completion was not available in that file. It works just fine on the main.xml layout file. I kinda rely on code completion to learn and experiment. Any ideas why it's not working in my new file? Thanks, D. – codedog Jun 06 '10 at 10:21
-
android:angle="250" is causing application to crash, changed to 45 and worked fine. – Youssef Sep 01 '10 at 18:02
-
@youssef: I am not sure why it is happening. It worked fine for me in 5 different instances. Do you have the log from adb by any chance? – Legend Sep 01 '10 at 18:23
-
1same as allclaws, angle should be multiple of 45 : "XmlPullParserException: Binary XML file line #4
tag requires 'angle' attribute to be a multiple of 45" – Youssef Sep 02 '10 at 09:27 -
29It doesn't work well with selection-highlighting though: When top or bottom item is selected, it's colored background is rectangular and drawn on top of the round-cornered background. – Kris Van Bael Jul 27 '11 at 13:30
-
-
Hi, do you know why I can't use different gradients? Thanxs. – Guillermo Oramas R. Nov 16 '12 at 16:57
-
Thanks for the code. It works great. But how will I make the selection also curved? – Sachin Thampan Nov 13 '13 at 05:28
-
and how to make sure it's still in round corner even top/bottom item is clicked? – suitianshi Feb 10 '14 at 10:08
-
Is there any possibility to set different color for each rows and have rounded corners? – Lukas Sagner Sep 06 '15 at 18:20
-
Yes, there is. Just set xml with rounded corners to item layout and then in adapter call: GradientDrawable drawable = (GradientDrawable)rowView.getBackground(); drawable.setColor(Color.parseColor(myObject.getBackgroundColor())); rowView.setBackground(drawable); – Lukas Sagner Sep 07 '15 at 20:16
Although that did work, it took out the entire background colour as well. I was looking for a way to do just the border and just replace that XML layout code with this one and I was good to go!
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke android:width="4dp" android:color="#FF00FF00" />
<padding android:left="7dp" android:top="7dp"
android:right="7dp" android:bottom="7dp" />
<corners android:radius="4dp" />
</shape>

- 16,975
- 20
- 76
- 105
-
Also check out [this answer](http://stackoverflow.com/questions/5646944/how-to-set-shapes-opacity) – ThomasRS Mar 21 '12 at 11:57
@kris-van-bael
For those having issues with selection highlight for the top and bottom row where the background rectangle shows up on selection you need to set the selector for your listview to transparent color.
listView.setSelector(R.color.transparent);
In color.xml just add the following -
<color name="transparent">#00000000</color>

- 226
- 3
- 5
-
5it didn't work for me. I added the following line, however, and it got rid of it: `android:cacheColorHint="@android:color/transparent"` – cesar Jan 10 '12 at 03:37
-
1This definitely fixed the selection issue for me - thanks! You can also use android.R.color.transparent for the Selector color instead of creating your own. – greg7gkb May 23 '12 at 04:20
-
3Instead of doing it programatically, add this to your ListView in the XML layout to hide selection color: android:listSelector="#00000000" – Elad Nava Sep 14 '12 at 18:21
-
@alvins Is there any way to make Layout selectable for highlighting like list view item? – Bharat Dodeja Jun 26 '13 at 07:57
-
what should i do if i want to use an opaque color for listSelector? – suitianshi Feb 10 '14 at 10:11
Update
The solution these days is to use a CardView
with support for rounded corners built in.
Original answer*
Another way I found was to mask out your layout by drawing an image over the top of the layout. It might help you. Check out Android XML rounded clipped corners

- 29,432
- 22
- 140
- 255
The other answers are very useful, thanks to the authors!
But I could not see how to customise the rectangle when highlighting an item upon selection rather than disabling the highlighting @alvins @bharat dojeha.
The following works for me to create a rounded list view item container with no outline and a lighter grey when selected of the same shape:
Your xml needs to contain a selector such as e.g. ( in res/drawable/customshape.xml):
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" >
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke android:width="8dp" android:color="@android:color/transparent" />
<padding android:left="14dp" android:top="14dp"
android:right="14dp" android:bottom="14dp" />
<corners android:radius="10dp" />
<gradient
android:startColor="@android:color/background_light"
android:endColor="@android:color/transparent"
android:angle="225"/>
</shape>
</item>
<item android:state_pressed="false">
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke android:width="8dp" android:color="@android:color/transparent" />
<padding android:left="14dp" android:top="14dp"
android:right="14dp" android:bottom="14dp" />
<corners android:radius="10dp" />
<gradient
android:startColor="@android:color/darker_gray"
android:endColor="@android:color/transparent"
android:angle="225"/>
</shape>
</item>
Then you need to implement a list adapter and override the getView method to set the custom selector as background
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//snip
convertView.setBackgroundResource(R.drawable.customshape);
//snip
}
and need to also 'hide' the default selector rectangle e.g in onCreate (I also hide my thin grey divider line between the items):
listView.setSelector(android.R.color.transparent);
listview.setDivider(null);
This approach solves a general solution for drawables, not just ListViewItem with various selection states.

- 1,179
- 7
- 10
Yet another solution to selection highlight problems with first, and last items in the list:
Add padding to the top and bottom of your list background equal to or greater than the radius. This ensures the selection highlighting doesn't overlap with your corner curves.
This is the easiest solution when you need non-transparent selection highlighting.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="@color/listbg" />
<stroke
android:width="2dip"
android:color="#D5D5D5" />
<corners android:radius="10dip" />
<!-- Make sure bottom and top padding match corner radius -->
<padding
android:bottom="10dip"
android:left="2dip"
android:right="2dip"
android:top="10dip" />
</shape>

- 10,953
- 2
- 31
- 48
actually, i think the best solution is described on this link:
http://blog.synyx.de/2011/11/android-listview-with-rounded-corners/
in short, it uses a different background for the top, middle and bottom items, so that the top and bottom ones would be rounded.

- 114,585
- 152
- 739
- 1,270
This was incredibly handy to me. I would like to suggest another workaround to perfectly highlight the rounded corners if you are using your own CustomAdapter
.
Defining XML Files
First of all, go inside your drawable folder and create 4 different shapes:
shape_top
<gradient android:startColor="#ffffff" android:endColor="#ffffff" android:angle="270"/> <corners android:topLeftRadius="10dp" android:topRightRadius="10dp"/>
shape_normal
<gradient android:startColor="#ffffff" android:endColor="#ffffff" android:angle="270"/> <corners android:topLeftRadius="10dp" android:topRightRadius="10dp"/>
shape_bottom
<gradient android:startColor="#ffffff" android:endColor="#ffffff" android:angle="270"/> <corners android:bottomRightRadius="10dp" android:bottomRightRadius="10dp"/>
shape_rounded
<gradient android:startColor="#ffffff" android:endColor="#ffffff" android:angle="270"/> <corners android:topLeftRadius="10dp" android:topRightRadius="10dp" android:bottomRightRadius="10dp" android:bottomRightRadius="10dp"/>
Now, create a different row layout for each shape, i.e. for shape_top
:
You can also do this programatically changing the background.
<TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="20dp" android:layout_marginRight="10dp" android:fontFamily="sans-serif-light" android:text="TextView" android:textSize="22dp" /> <TextView android:id="@+id/txtValue1" android:layout_width="match_parent" android:layout_height="48dp" android:textSize="22dp" android:layout_gravity="right|center" android:gravity="center|right" android:layout_marginLeft="20dp" android:layout_marginRight="35dp" android:text="Fix" android:scaleType="fitEnd" />
And define a selector for each shaped-list, i.e. for shape_top
:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Selected Item -->
<item android:state_selected="true"
android:drawable="@drawable/shape_top" />
<item android:state_activated="true"
android:drawable="@drawable/shape_top" />
<!-- Default Item -->
<item android:state_selected="false"
android:drawable="@android:color/transparent" />
</selector>
Change your CustomAdapter
Finally, define the layout options inside your CustomAdapter
:
if(position==0)
{
convertView = mInflater.inflate(R.layout.list_layout_top, null);
}
else
{
convertView = mInflater.inflate(R.layout.list_layout_normal, null);
}
if(position==getCount()-1)
{
convertView = mInflater.inflate(R.layout.list_layout_bottom, null);
}
if(getCount()==1)
{
convertView = mInflater.inflate(R.layout.list_layout_unique, null);
}
And that's done!

- 14,105
- 13
- 56
- 97
to make border u have to make another xml file with property of solid and corners in the drawable folder and calls it in background

- 81
- 1
- 1
I'm using a custom view that I layout on top of the other ones and that just draws the 4 small corners in the same color as the background. This works whatever the view contents are and does not allocate much memory.
public class RoundedCornersView extends View {
private float mRadius;
private int mColor = Color.WHITE;
private Paint mPaint;
private Path mPath;
public RoundedCornersView(Context context) {
super(context);
init();
}
public RoundedCornersView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.RoundedCornersView,
0, 0);
try {
setRadius(a.getDimension(R.styleable.RoundedCornersView_radius, 0));
setColor(a.getColor(R.styleable.RoundedCornersView_cornersColor, Color.WHITE));
} finally {
a.recycle();
}
}
private void init() {
setColor(mColor);
setRadius(mRadius);
}
private void setColor(int color) {
mColor = color;
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAntiAlias(true);
invalidate();
}
private void setRadius(float radius) {
mRadius = radius;
RectF r = new RectF(0, 0, 2 * mRadius, 2 * mRadius);
mPath = new Path();
mPath.moveTo(0,0);
mPath.lineTo(0, mRadius);
mPath.arcTo(r, 180, 90);
mPath.lineTo(0,0);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
/*Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRect(0, 0, mRadius, mRadius, paint);*/
int w = getWidth();
int h = getHeight();
canvas.drawPath(mPath, mPaint);
canvas.save();
canvas.translate(w, 0);
canvas.rotate(90);
canvas.drawPath(mPath, mPaint);
canvas.restore();
canvas.save();
canvas.translate(w, h);
canvas.rotate(180);
canvas.drawPath(mPath, mPaint);
canvas.restore();
canvas.translate(0, h);
canvas.rotate(270);
canvas.drawPath(mPath, mPaint);
}
}

- 6,893
- 3
- 39
- 55
There are different ways to achieve it. The latest approach is using CardView for each ListItem component. Here are some steps.
- Create a layout resource file; let's name it "listitem.xml
- Copy and paste the under enclosed Listitem.xml layout body into it.
- Create RowItem class for each listitem data; later you will instantiate this to assign values for each list item. Check Code below, RowItem.class.
- Create a custom ListAdapter; let's name it ListAdapter.class, and inflate this (#1) list item layout for each list item (Check the second code snippet for this one)
- Set this adapter (#3) the way you set default adapters inside an activity the listview belongs to. maybe the only difference would be you first have to instantiate RowItem class with values and add RowItem object to your adapter then notify your adapter that the data is changed.
**listitem.xml**
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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="wrap_content"
android:orientation="vertical">
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alignmentMode="alignMargins"
android:columnCount="1"
android:columnOrderPreserved="false"
android:rowCount="1">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_columnWeight="1"
android:layout_margin="6dp"
app:cardCornerRadius="8dp"
app:cardElevation="6dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/sampleiconimageID"
android:layout_width="60dp"
android:layout_height="60dp"
android:padding="5dp"/>
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/titleoflistview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Main Heading"
android:textStyle="bold" />
<TextView
android:id="@+id/samplesubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sub Heading"
/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</GridLayout>
</LinearLayout>
RowItem.Class
public class RowItem {
private String heading;
private String subHeading;
private int smallImageName;
private String datetime;
private int count;
public void setHeading( String theHeading ) {
this.heading = theHeading;
}
public String getHeading() {
return this.heading;
}
public void setSubHeading( String theSubHeading ) {
this.subHeading = theSubHeading;
}
public String getSubHeading( ) {
return this.subHeading;
}
public void setSmallImageName(int smallName) {
this.smallImageName = smallName;
}
public int getSmallImageName() {
return this.smallImageName;
}
public void setDate(String datetime) {
this.datetime = datetime;
}
public String getDate() {
return this.datetime;
}
public void setCount(int count) {
this.count = count;
}
public int getCount() {
return this.count;
}
}
Sample ListAdapter
public class ListAdapter extends BaseAdapter {
private ArrayList<RowItem> singleRow;
private LayoutInflater thisInflater;
public ListAdapter(Context context, ArrayList<RowItem> aRow){
this.singleRow = aRow;
thisInflater = ( LayoutInflater.from(context) );
}
@Override
public int getCount() {
return singleRow.size(); }
@Override
public Object getItem(int position) {
return singleRow.get( position ); }
@Override
public long getItemId(int position) {
return position;
}
public View getView(int position, View view, ViewGroup parent) {
if (view == null) {
view = thisInflater.inflate( R.layout.mylist2, parent, false );
//set listview objects here
//example
TextView titleText = (TextView) view.findViewById(R.id.titleoflistview);
RowItem currentRow = (RowItem) getItem(position);
titleText.setText( currentRow.getHeading() );
}
return view;
// LayoutInflater inflater=.getLayoutInflater();
// View rowView=inflater.inflate(R.layout.mylist, null,true);
//
// titleText.setText(maintitle[position]);
// subtitleText.setText(subtitle[position]);
// return null;
};
}

- 49
- 3