¿Cómo creo un ListView con esquinas redondeadas en Android?


Respuestas:


371

Aquí hay una forma de hacerlo (¡Sin embargo, gracias a la documentación de Android!):

Agregue lo siguiente en un archivo (por ejemplo, Customhape.xml) y luego colóquelo en (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> 

Una vez que haya terminado de crear este archivo, simplemente configure el fondo de una de las siguientes maneras:

A través del código: listView.setBackgroundResource(R.drawable.customshape);

A través de XML , simplemente agregue el siguiente atributo al contenedor (por ejemplo, LinearLayout o cualquier campo):

android:background="@drawable/customshape"

Espero que alguien lo encuentre útil...


2
Gracias por el gran consejo. Solo para su información, el pegado de copia me dio una excepción en tiempo de ejecución que decía: "XmlPullParserException: la etiqueta de línea de archivo XML binario # 4 <gradient> requiere que el atributo 'angle' sea un múltiplo de 45". Se soluciona fácilmente cambiando el ángulo a 270.
allclaws

Gracias por la solución ... Pero no sé por qué eso podría estar sucediendo ... ¿Encontraste alguna razón específica?
Leyenda

@teedyay: En cualquier momento amigo :)
Leyenda

1
igual que allclaws, el ángulo debe ser múltiplo de 45: "XmlPullParserException: la etiqueta de línea de archivo XML binario # 4 <gradient> requiere que el atributo 'angle' sea un múltiplo de 45"
Youssef

29
Sin embargo, no funciona bien con el resaltado de selección: cuando se selecciona el elemento superior o inferior, su fondo de color es rectangular y se dibuja sobre el fondo redondeado.
Kris Van Bael

56

Aunque eso funcionó, también eliminó todo el color de fondo. Estaba buscando una manera de hacer solo el borde y reemplazar ese código de diseño XML con este, ¡y estaba listo!

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

Consulte también esta respuesta
ThomasRS

12

@ kris-van-bael

Para aquellos que tienen problemas con la selección, resalte para la fila superior e inferior donde aparece el rectángulo de fondo en la selección, necesita configurar el selector para su vista de lista en color transparente.

listView.setSelector(R.color.transparent);

En color.xml solo agregue lo siguiente:

<color name="transparent">#00000000</color>

55
No funcionó para mí. Sin embargo, agregué la siguiente línea y la eliminé:android:cacheColorHint="@android:color/transparent"
cesar

1
Esto definitivamente solucionó el problema de selección para mí, ¡gracias! También puede usar android.R.color.transparent para el color Selector en lugar de crear el suyo.
greg7gkb

3
En lugar de hacerlo programáticamente, agregue esto a su ListView en el diseño XML para ocultar el color de selección: android: listSelector = "# 00000000"
Elad Nava

@alvins ¿Hay alguna forma de hacer que el diseño sea seleccionable para resaltar como elemento de vista de lista?
Bharat Dodeja

¿Qué debo hacer si quiero usar un color opaco para listSelector?
suitianshi

3

¡Las otras respuestas son muy útiles, gracias a los autores!

Pero no pude ver cómo personalizar el rectángulo al resaltar un elemento tras la selección en lugar de deshabilitar el resaltado @alvins @bharat dojeha.

Lo siguiente funciona para mí para crear un contenedor de elementos de vista de lista redondeada sin contorno y un gris más claro cuando se selecciona de la misma forma:

Su xml debe contener un selector como por ejemplo (en res / drawable / customhape.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>

Luego, debe implementar un adaptador de lista y anular el método getView para establecer el selector personalizado como fondo

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

y también necesito 'ocultar' el rectángulo selector predeterminado, por ejemplo, en onCreate (también oculto mi delgada línea divisoria gris entre los elementos):

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

Este enfoque resuelve una solución general para elementos dibujables, no solo ListViewItem con varios estados de selección.



2

Otra solución más para la selección resalta los problemas con los primeros y últimos elementos de la lista:

Agregue relleno en la parte superior e inferior de su fondo de lista igual o mayor que el radio. Esto garantiza que el resaltado de selección no se superponga con las curvas de las esquinas.

Esta es la solución más fácil cuando necesita resaltado de selección no transparente.

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


1

Esto fue increíblemente útil para mí. Me gustaría sugerir otra solución alternativa para resaltar perfectamente las esquinas redondeadas si está utilizando su propiaCustomAdapter .

Definición de archivos XML

En primer lugar, vaya a su carpeta dibujable y cree 4 formas diferentes:

  • shape_top

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"/>

  • forma_normal

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"/>

  • forma_bottom

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:bottomRightRadius="10dp"
        android:bottomRightRadius="10dp"/>

  • rodeado de forma

    <gradient
        android:startColor="#ffffff"
        android:endColor="#ffffff"
        android:angle="270"/>
    <corners
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp"
        android:bottomRightRadius="10dp"
        android:bottomRightRadius="10dp"/>

Ahora, cree un diseño de fila diferente para cada forma, es decir, para shape_top:

  • También puede hacer esto cambiando programáticamente el fondo.

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

Y defina un selector para cada lista conformada, es decir, para 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>

Cambie su Adaptador personalizado

Finalmente, defina las opciones de diseño dentro de su 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);
}

¡Y ya está!


1

para hacer el borde, debe hacer otro archivo xml con propiedad de sólidos y esquinas en la carpeta dibujable y lo llama en segundo plano


0

Estoy usando una vista personalizada que diseño encima de las otras y que solo dibuja las 4 esquinas pequeñas del mismo color que el fondo. Esto funciona independientemente de los contenidos de la vista y no asigna mucha memoria.

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);
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.