Comment faire une vue sur android avec des coins arrondis
j'essaie de faire une vue sur android avec des bords arrondis. La solution que j'ai trouvée jusqu'à présent est de définir une forme avec des coins arrondis et de l'utiliser comme le fond de cette vue.
voici ce que j'ai fait, définir un drawable comme indiqué ci-dessous
<padding
android:top="2dp"
android:bottom="2dp"/>
<corners android:bottomRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp"/>
maintenant j'ai utilisé ceci comme arrière-plan pour ma mise en page comme ci-dessous
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="@drawable/rounded_corner">
Cela fonctionne parfaitement bien, je peut voir que la vue a des bords arrondis.
mais ma mise en page a beaucoup d'autres vues d'enfant dans elle disent une ImageView ou une MapView. Quand je place une vue D'image à l'intérieur de la mise en page ci-dessus, les coins de l'image ne sont pas coupés/recadrés, à la place elle apparaît pleine.
j'ai vu d'autres solutions de rechange pour le faire fonctionner comme celui expliqué ici .
mais existe-t-il une méthode pour placer les coins arrondis pour un la vue et l'ensemble de ses les opinions de l'enfant sont contenues dans cette vue principale qui a été arrondie les coins?
Merci.
15 réponses
une autre approche consiste à créer une classe de mise en page personnalisée comme celle ci-dessous. Cette mise en page dessine d'abord son contenu sur un bitmap offscreen, masque le bitmap offscreen avec un rect arrondi et puis dessine le bitmap offscreen sur la toile réelle.
Je l'ai essayé et il semble fonctionner (au moins pour mon simple testcase). Il va de soi que cela affectera les performances par rapport à une mise en page régulière.
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;
}
}
utilisez ceci comme une disposition normale:
<com.example.RoundedCornerLayout
android:layout_width="200dp"
android:layout_height="200dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/test"/>
<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ff0000"
/>
</com.example.RoundedCornerLayout>
de forme.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#f6eef1" />
<stroke
android:width="2dp"
android:color="#000000" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
<corners android:radius="5dp" />
</shape>
et à l'intérieur de vous mise en page
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="@drawable/shape">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/your image"
android:background="@drawable/shape">
</LinearLayout>
ou vous pouvez utiliser un android.support.v7.widget.CardView
comme ainsi:
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="@color/white"
card_view:cardCornerRadius="4dp">
<!--YOUR CONTENT-->
</android.support.v7.widget.CardView>
si vous avez un problème en ajoutant des écouteurs tactiles au layout. Utilisez ce layout comme layout parent.
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.restoreToCount(count);
}
}
comme
<?xml version="1.0" encoding="utf-8"?>
<com.example.view.RoundedCornerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/patentItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="20dp">
... your child goes here
</RelativeLayout>
</com.example.view.RoundedCornerLayout>
créer un round xml.xml dans le dossier drawable
<solid android:color="#FFFFFF" />
<stroke android:width=".05dp" android:color="#d2d2d2" />
<corners android:topLeftRadius="5dp" android:topRightRadius="5dp" android:bottomLeftRadius="5dp" android:bottomRightRadius="5dp" />
utiliser rond.xml à l'arrière-plan des éléments..Il donnera des coins arrondis
dans Android L, vous serez en mesure d'utiliser juste vue.setClipToOutline pour obtenir cet effet. Dans les versions précédentes, il n'y a aucun moyen de simplement clipper le contenu d'un groupe de vue aléatoire dans une certaine forme.
vous devrez penser à quelque chose qui vous donnerait un effet similaire:
-
si vous n'avez besoin que de coins arrondis dans L'ImageView, vous pouvez utiliser un shader pour "peindre" l'image sur la forme que vous êtes en utilisant comme toile de fond. Jetez un oeil à cette bibliothèque pour un exemple.
-
si vous avez vraiment besoin que chaque enfant soit coupé, peut-être Pouvez-vous avoir une autre vue sur votre disposition? Un avec un fond de la couleur que vous utilisez, et un "trou" rond au milieu? Vous pouvez en fait créer un groupe de vue personnalisé qui dessine cette forme au-dessus de chaque enfant dépassant la méthode onDraw.
la réponse de Jaap van Hengstum fonctionne bien mais je pense qu'il est cher et si nous appliquons cette méthode sur un bouton par exemple, l'effet de toucher est perdu puisque la vue est rendue comme un bitmap.
pour moi la meilleure méthode et la plus simple consiste à appliquer un masque sur la vue, comme cela:
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
float cornerRadius = <whatever_you_want>;
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);
}
suivez ce tutoriel et toute la discussion sous elle - http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners /
selon ce post écrit par Guy Romain, l'un des principaux développeurs de L'ensemble Android UI toolkit, il est possible de faire un conteneur (et toutes ses vues enfant) avec des coins arrondis, mais il a expliqué qu'il trop cher (à partir de performances de les problèmes de rendu).
je vous recommande d'aller selon son poteau, et si vous voulez coins arrondis, puis mettre en œuvre coins arrondis ImageView
selon ce poteau. ensuite, vous pouvez le placer dans un conteneur avec n'importe quel arrière-plan, et vous obtiendrez l'effet que vous souhaitez.
c'est ce que j'ai fait aussi finalement.
le lien de tutoriel que vous avez fourni semble suggérer que vous devez définir les propriétés layout_width et layout_height, de vos éléments enfant à match_parent.
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent">
Différence de Jaap van Hengstum réponse:
- Utiliser BitmapShader au lieu de masque bitmap.
- créer bitmap une seule fois.
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.restoreToCount(count);
}
}
le CardView
a fonctionné pour moi dans API 27 dans Android Studio 3.0.1. Le colorPrimary
a été référencé dans le fichier res/values/colors.xml
et n'est qu'un exemple. Pour le layout_width de 0dp
il s'étendra à la largeur du parent. Vous devrez configurer les contraintes et la largeur/hauteur de vos besoins.
<android.support.v7.widget.CardView
android:id="@+id/cardView"
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:cardCornerRadius="4dp"
app:cardBackgroundColor="@color/colorPrimary">
<!-- put your content here -->
</android.support.v7.widget.CardView>
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;
}
utiliser la forme en xml avec le rectangle.définissez la propriété de rayon inférieur ou supérieur comme voulu.ensuite, appliquez ce xml comme arrière-plan à la vue ur....ou...utilisez des gradients pour le faire à partir du code.