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.

  • Android - diseño de fila de 3 columnas - ¿Cómo puedo hacer que ocupe un porcentaje de la pantalla?
  • Disposiciones de Google Play Store. Problemas con apktool
  • Cómo determinar la dirección de desplazamiento de ListView
  • El editor de diseño de Android Studio no puede mostrar vistas personalizadas
  • Android, "Error en un archivo XML: aborting build."
  • Cómo reemplazar / cambiar el botón de la imagen mediante programación android
  • Detener Android desde el diseño de todas mis vistas
  • ¿Cuál es una buena manera de probar los métodos onMeasure / onLayout / onDraw de una vista personalizada?
  • Escala Android de imágenes a densidad de pantalla
  • RecycleView roba el foco cuando está dentro de un NestedScrollView
  • ¿Por qué RecyclerView.notifyItemChanged () creará un nuevo ViewHolder y utilizará tanto el antiguo ViewHolder como el nuevo?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.