179

如何在 Android 中创建带圆角的 ListView?

4

11 回答 11

377

这是一种方法(感谢 Android 文档!):

将以下内容添加到文件中(例如 customshape.xml),然后将其放入(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> 

完成创建此文件后,只需通过以下方式之一设置背景:

通过代码: listView.setBackgroundResource(R.drawable.customshape);

通过 XML,只需将以下属性添加到容器(例如:LinearLayout 或任何字段):

android:background="@drawable/customshape"

希望有人觉得它有用...

于 2009-11-05T20:05:02.557 回答
57

尽管这确实有效,但它也消除了整个背景颜色。我正在寻找一种只做边框的方法,然后用这个替换那个 XML 布局代码,我很高兴!

<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> 
于 2011-04-03T02:34:35.740 回答
12

@kris-van-bael

对于那些在选择时显示背景矩形的顶行和底行的选择突出显示问题的人,您需要将列表视图的选择器设置为透明颜色。

listView.setSelector(R.color.transparent);

在 color.xml 中只需添加以下内容 -

<color name="transparent">#00000000</color>
于 2011-12-29T02:01:52.820 回答
4

更新

这些天的解决方案是使用CardView支持圆角的内置圆角。


原始答案*

我发现的另一种方法是通过在布局顶部绘制图像来掩盖您的布局。它可能会帮助你。查看Android XML 圆角剪裁

于 2011-11-29T15:18:22.903 回答
3

感谢作者,其他答案非常有用!

但是我看不到如何在选择时突出显示项目而不是禁用突出显示@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:

您的 xml 需要包含一个选择器,例如(在 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>

然后你需要实现一个列表适配器并重写getView方法将自定义选择器设置为背景

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //snip
        convertView.setBackgroundResource(R.drawable.customshape);
        //snip
    }

并且还需要“隐藏”默认选择器矩形,例如在 onCreate 中(我还隐藏了项目之间的灰色细分隔线):

listView.setSelector(android.R.color.transparent);
listview.setDivider(null);

这种方法解决了可绘制的通用解决方案,而不仅仅是具有各种选择状态的 ListViewItem。

于 2015-03-06T12:22:37.327 回答
2

另一个选择的解决方案突出了列表中第一个和最后一个项目的问题:

在列表背景的顶部和底部添加等于或大于半径的填充。这可确保选择突出显示不会与您的角曲线重叠。

当您需要不透明的选择突出显示时,这是最简单的解决方案。

<?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>
于 2014-02-27T19:37:21.980 回答
1

实际上,我认为此链接描述了最佳解决方案:

http://blog.synyx.de/2011/11/android-listview-with-rounded-corners/

简而言之,它为顶部、中间和底部的项目使用不同的背景,以便顶部和底部的项目被圆角。

于 2013-06-19T06:24:06.147 回答
1

这对我来说非常方便。如果您使用自己的CustomAdapter.

定义 XML 文件

首先,进入你的drawable文件夹并创建4个不同的形状:

  • 形状顶部

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

  • 形状底部

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

现在,为每个形状创建不同的行布局,即shape_top

  • 您也可以以编程方式更改背景。

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

并为每个形状列表定义一个选择器,即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>

更改您的 CustomAdapter

最后,在你的内部定义布局选项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);
}

这样就完成了!

于 2015-07-16T20:58:06.257 回答
1

要制作边框,您必须在可绘制文件夹中创建另一个具有实体和角属性的 xml 文件,并在后台调用它

于 2016-10-20T13:05:41.373 回答
0

我正在使用一个自定义视图,该视图布局在其他视图之上,并且仅绘制与背景颜色相同的 4 个小角。无论视图内容是什么,这都有效,并且不会分配太多内存。

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);
    }
}
于 2017-01-28T15:45:28.120 回答
0

有不同的方法来实现它。最新的方法是对每个 ListItem 组件使用 CardView。这里有一些步骤。

  1. 创建布局资源文件;让我们将其命名为“listitem.xml
  2. 将下面的Listitem.xml布局主体复制并粘贴到其中。
  3. 为每个 listitem 数据创建 RowItem 类;稍后您将实例化它以为每个列表项分配值。检查下面的代码,RowItem.class。
  4. 创建自定义 ListAdapter;让我们将其命名为 ListAdapter.class,并为每个列表项扩展此(#1)列表项布局(检查第二个代码片段)
  5. 在列表视图所属的活动中设置默认适配器的方式设置此适配器(#3)。也许唯一的区别是您首先必须用值实例化 RowItem 类并将 RowItem 对象添加到您的适配器,然后通知您的适配器数据已更改。
**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>

行项目类

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

}

示例列表适配器

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;

    };
}
于 2020-07-26T11:10:56.793 回答