Diseño personalizado que redondea las esquinas de su contenido

Quisiera crear un ViewGroup genérico que pueda entonces ser reutilizado en disposiciones XML para redondear las esquinas de cualquier cosa que se pone en él.

Por alguna razón canvas.clipPath() no parece tener un efecto. ¿Qué estoy haciendo mal?

Aquí está el código Java:

 package rounded; import static android.graphics.Path.Direction.CCW; public class RoundedView extends FrameLayout { private float radius; private Path path = new Path(); private RectF rect = new RectF(); public RoundedView(Context context, AttributeSet attrs) { super(context, attrs); this.radius = attrs.getAttributeFloatValue(null, "corner_radius", 0f); } @Override protected void onDraw(Canvas canvas) { int savedState = canvas.save(); float w = getWidth(); float h = getHeight(); path.reset(); rect.set(0, 0, w, h); path.addRoundRect(rect, radius, radius, CCW); path.close(); boolean debug = canvas.clipPath(path); super.onDraw(canvas); canvas.restoreToCount(savedState); } } 

Uso en XML:

 <?xml version="1.0" encoding="utf-8"?> <rounded.RoundedView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" corner_radius="40.0" > <RelativeLayout android:id="@+id/RelativeLayout1" android:layout_width="match_parent" android:layout_height="match_parent" > ... </RelativeLayout> </rounded.RoundedView> 

7 Solutions collect form web for “Diseño personalizado que redondea las esquinas de su contenido”

La forma correcta de crear un ViewGroup que clip a sus hijos es hacerlo en el método dispatchDraw (Canvas).

Este es un ejemplo de cómo puede grabar a los niños de un grupo de vistas con un círculo:

 private Path path = new Path(); @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // compute the path float halfWidth = w / 2f; float halfHeight = h / 2f; float centerX = halfWidth; float centerY = halfHeight; path.reset(); path.addCircle(centerX, centerY, Math.min(halfWidth, halfHeight), Path.Direction.CW); path.close(); } @Override protected void dispatchDraw(Canvas canvas) { int save = canvas.save(); canvas.clipPath(circlePath); super.dispatchDraw(canvas); canvas.restoreToCount(save); } 

El método dispatchDraw es el que se llama para recortar a los niños. No hay necesidad de setWillNotDraw (false) si su diseño sólo clip de sus hijos.

Esta imagen se obtiene con el código de arriba, me acaba de ampliar Facebook ProfilePictureView (que es un FrameLayout incluyendo un cuadrado ImageView con la foto de perfil de facebook):

Recorte de círculo

Así que para lograr un borde redondo hacer algo como esto:

 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // compute the path path.reset(); rect.set(0, 0, w, h); path.addRoundRect(rect, radius, radius, Path.Direction.CW); path.close(); } @Override protected void dispatchDraw(Canvas canvas) { int save = canvas.save(); canvas.clipPath(path); super.dispatchDraw(canvas); canvas.restoreToCount(save); } 

Recorte de borde redondo

Usted puede crear realmente cualquier camino complejo 🙂

Recuerde que puede llamar a clipPath varias veces con la operación "Op" que desea cruzar el recorte múltiple de la manera que desee.

NOTA: He creado la ruta en el onSizeChanged porque hacerlo en el onDraw es malo para el rendimiento.

NOTA2: el recorte de una ruta se realiza sin anti-aliasing: / por lo que si desea bordes lisos tendrá que hacerlo de alguna otra manera. No estoy enterado de ninguna manera de hacer que el recorte utilice anti-aliasing ahora.

Buena suerte

Puede anular el método de draw(Canvas canvas) :

 public class RoundedLinearLayout extends LinearLayout { Path mPath; float mCornerRadius; public RoundedLinearLayout(Context context) { super(context); } public RoundedLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); } public RoundedLinearLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public void draw(Canvas canvas) { canvas.save(); canvas.clipPath(mPath); super.draw(canvas); canvas.restore(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); RectF r = new RectF(0, 0, w, h); mPath = new Path(); mPath.addRoundRect(r, mCornerRadius, mCornerRadius, Direction.CW); mPath.close(); } public void setCornerRadius(int radius) { mCornerRadius = radius; invalidate(); } } 

ViewGroup (y, por lo tanto, sus subclases) establece un indicador que indica que no realiza ningún dibujo de forma predeterminada. En la fuente se ve algo así:

 // ViewGroup doesn't draw by default if (!debugDraw()) { setFlags(WILL_NOT_DRAW, DRAW_MASK); } 

Así que su onDraw(...) probablemente no se golpeó en absoluto ahora. Si desea realizar cualquier dibujo manual, llame a setWillNotDraw(false) .

No se olvide de pedir que onDraw se llame con setWillNotDraw (false); Y establecer un valor para mRadius entonces sólo hacer algo como eso:

 @Override protected void onDraw(Canvas canvas) { mPath.reset(); mRect.set(0, 0, canvas.getWidth(), canvas.getHeight()); mPath.addRoundRect(mRect, mRadius, mRadius, Direction.CCW); mPath.close(); canvas.clipPath(mPath); } 

OnDraw de FrameLayout no se llama si el fondo de Layout de Ur no está establecido;

Debe reemplazar dispatchDraw;

U necesidad de anular el método drawChild () para recortar childViews.

 @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { int flag = canvas.save(); canvas.clipPath(pathToClip); boolean result=super.drawChild(canvas, child, drawingTime); canvas.restoreToCount(flag); return result; } 

Si u desea recortar el fondo de la ViewGroup demasiado, reemplazar draw () en lugar de eso.

 @Override public void draw(Canvas canvas) { int flag = canvas.save(); canvas.clipPath(pathToClip); super.draw(canvas); canvas.restoreToCount(flag); } 

¿Por qué no sólo definir un ShapeDrawable como el fondo de su diseño y sólo cambiar el radio de la esquina de la drawable en tiempo de ejecución.

  • FloatingActionButton en Fragmento oculto en la barra de herramientas colapsando
  • Cómo centrar y alinear a la izquierda y derecha los iconos de ActionBar en Android
  • Cómo configurar el color del borde de la casilla de verificación
  • ¿Cómo manejar clics / toques en componentes personalizados repetidos?
  • Adición de un fondo de color y un radio de borde a un Layout
  • Cómo establecer el enfoque en un elemento en la barra de acción en el lanzamiento
  • Cómo puedo cambiar la alineación de las vistas secundarias de la barra de herramientas
  • ¿Qué significa elipsis en android?
  • ¿Es posible crear un ToggleButton sin texto?
  • Android ScrollView y los botones en la parte inferior de la pantalla
  • Cambiar el color de línea inferior de EditText con appcompat v7
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.