Cómo hacer una vista en Android con esquinas redondeadas

Estoy tratando de hacer una vista en Android con bordes redondeados. La solución que encontré hasta ahora es definir una forma con esquinas redondeadas y usarla como fondo de esa vista.

Aquí está lo que hice, defina un dibujable como se indica a continuación

  

Ahora lo usé como fondo para mi diseño, como se muestra a continuación

  

Esto funciona perfectamente bien, puedo ver que la vista tiene bordes redondeados.

Pero mi diseño tiene muchas otras vistas secundarias en él. Diga un ImageView o un MapView. Cuando coloco un ImageView dentro del diseño anterior, las esquinas de la imagen no se recortan / recortan, sino que aparecen llenas.

He visto otras soluciones para que funcione como la que se explica aquí .

¿Pero hay un método para establecer esquinas redondeadas para una vista y todas sus vistas secundarias están contenidas dentro de esa vista principal que tiene esquinas redondeadas?

Gracias.

Otro enfoque es hacer una clase de diseño personalizado como la siguiente. Este diseño primero dibuja su contenido en un bitmap fuera de pantalla, enmascara el bitmap fuera de pantalla con un rect redondo y luego dibuja el bitmap fuera de pantalla en el canvas real.

Lo intenté y parece funcionar (al menos para mi caso de prueba simple). Por supuesto, afectará el rendimiento en comparación con un diseño regular.

 package com.example; import android.content.Context; import android.graphics.*; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.widget.FrameLayout; public class RoundedCornerLayout extends FrameLayout { private final static float CORNER_RADIUS = 40.0f; private Bitmap maskBitmap; private Paint paint, maskPaint; private float cornerRadius; public RoundedCornerLayout(Context context) { super(context); init(context, null, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics); paint = new Paint(Paint.ANTI_ALIAS_FLAG); maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); setWillNotDraw(false); } @Override public void draw(Canvas canvas) { Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); Canvas offscreenCanvas = new Canvas(offscreenBitmap); super.draw(offscreenCanvas); if (maskBitmap == null) { maskBitmap = createMask(canvas.getWidth(), canvas.getHeight()); } offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint); canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint); } private Bitmap createMask(int width, int height) { Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8); Canvas canvas = new Canvas(mask); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.WHITE); canvas.drawRect(0, 0, width, height, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint); return mask; } } 

Use esto como un diseño normal:

     

shape.xml

       

y dentro de ti diseño

    

O puede usar un android.support.v7.widget.CardView así:

    

Si tiene problemas al agregar oyentes táctiles al diseño. Use este diseño como diseño principal.

 import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.graphics.Region; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.widget.FrameLayout; public class RoundedCornerLayout extends FrameLayout { private final static float CORNER_RADIUS = 6.0f; private float cornerRadius; public RoundedCornerLayout(Context context) { super(context); init(context, null, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics); setLayerType(View.LAYER_TYPE_SOFTWARE, null); } @Override protected void dispatchDraw(Canvas canvas) { int count = canvas.save(); final Path path = new Path(); path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), cornerRadius, cornerRadius, Path.Direction.CW); canvas.clipPath(path, Region.Op.REPLACE); canvas.clipPath(path); super.dispatchDraw(canvas); canvas.restreToCount(count); } } 

como

    ... your child goes here   

crea un xml round.xml en una carpeta dibujable

    

luego usa round.xml como fondo para los elementos … Luego dará esquinas redondeadas

En Android L, solo podrá usar View.setClipToOutline para obtener ese efecto. En versiones anteriores, no hay forma de recortar los contenidos de un ViewGroup aleatorio en una forma determinada.

Tendrá que pensar en algo que le dé un efecto similar:

  • Si solo necesita esquinas redondeadas en ImageView, puede usar un sombreador para “pintar” la imagen sobre la forma que está utilizando como fondo. Echa un vistazo a esta biblioteca para ver un ejemplo.

  • Si realmente necesita que todos los niños sean recortados, ¿tal vez pueda otra vista sobre su diseño? ¿Uno con un fondo de cualquier color que esté usando y un “agujero” redondo en el medio? En realidad, podría crear un grupo de visualización personalizado que dibuje esa forma sobre cada uno de los niños que anula el método onDraw.

La respuesta de Jaap van Hengstum funciona muy bien, pero creo que es cara y si aplicamos este método en un botón, por ejemplo, el efecto táctil se pierde porque la vista se representa como un bitmap.

Para mí, el mejor método y el más simple consiste en aplicar una máscara en la vista, así:

 @Override protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { super.onSizeChanged(width, height, oldWidth, oldHeight); float cornerRadius = ; this.path = new Path(); this.path.addRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, Path.Direction.CW); } @Override protected void dispatchDraw(Canvas canvas) { if (this.path != null) { canvas.clipPath(this.path); } super.dispatchDraw(canvas); } 

siga este tutorial y toda la discusión debajo de élhttp://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/

de acuerdo con este post escrito por Guy Romain, uno de los principales desarrolladores de todo el conjunto de herramientas de interfaz de usuario de Android, es posible hacer un contenedor (y todas las vistas de su hijo) con esquinas redondeadas, pero explicó que es demasiado caro (a partir de representaciones de problemas de representación).

Te recomendaré ir de acuerdo con su publicación, y si quieres esquinas redondeadas, implementa las esquinas redondeadas ImageView según esta publicación. entonces, podrías colocarlo dentro de un contenedor con cualquier fondo, y obtendrás el efecto que desees.

eso es lo que hice también eventualmente.

El vínculo del tutorial que proporcionó parece sugerir que debe establecer las propiedades layout_width y layout_height, de los elementos secundarios para match_parent.

  

prueba esta propiedad con tu diseño lineal, te ayudará
herramientas: context = “. youractivity”

Diferencia de la respuesta de Jaap van Hengstum:

  1. Utilice BitmapShader en lugar de máscara de bitmap.
  2. Crear bitmap solo una vez.
 public class RoundedFrameLayout extends FrameLayout { private Bitmap mOffscreenBitmap; private Canvas mOffscreenCanvas; private BitmapShader mBitmapShader; private Paint mPaint; private RectF mRectF; public RoundedFrameLayout(Context context) { super(context); init(); } public RoundedFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RoundedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setWillNotDraw(false); } @Override public void draw(Canvas canvas) { if (mOffscreenBitmap == null) { mOffscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); mOffscreenCanvas = new Canvas(mOffscreenBitmap); mBitmapShader = new BitmapShader(mOffscreenBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setShader(mBitmapShader); mRectF = new RectF(0f, 0f, canvas.getWidth(), canvas.getHeight()); } super.draw(mOffscreenCanvas); canvas.drawRoundRect(mRectF, 8, 8, mPaint); } } 
 public class RoundedCornerLayout extends FrameLayout { private double mCornerRadius; public RoundedCornerLayout(Context context) { this(context, null, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); setLayerType(View.LAYER_TYPE_SOFTWARE, null); } public double getCornerRadius() { return mCornerRadius; } public void setCornerRadius(double cornerRadius) { mCornerRadius = cornerRadius; } @Override public void draw(Canvas canvas) { int count = canvas.save(); final Path path = new Path(); path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), (float) mCornerRadius, (float) mCornerRadius, Path.Direction.CW); canvas.clipPath(path, Region.Op.REPLACE); canvas.clipPath(path); super.draw(canvas); canvas.restreToCount(count); } } 

El CardView funcionó para mí en API 27 en Android Studio 3.0.1. El colorPrimary fue referenciado en el archivo res/values/colors.xml y es solo un ejemplo. Para el layout_width de 0dp , se extenderá al ancho del principal. Deberá configurar las restricciones y el ancho / alto según sus necesidades.

    
 public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) { Bitmap roundedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(roundedBitmap); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); final float roundPx = pixels; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return roundedBitmap; } 

Use la forma en xml con rectangle.set la propiedad de radio inferior o superior como desee.entonces aplique ese xml como fondo a su vista …. o … use gradientes para hacerlo desde el código.