Comment créer une mise en page aux coins arrondis? Je veux appliquer des coins arrondis à mon LinearLayout
.
Comment créer une mise en page aux coins arrondis? Je veux appliquer des coins arrondis à mon LinearLayout
.
Réponses:
1: Définissez layout_bg.xml dans drawables:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<stroke android:width="3dp" android:color="#B1BCBE" />
<corners android:radius="10dp"/>
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>
2: Ajoutez layout_bg.xml
comme arrière-plan à votre mise en page
android:background="@drawable/layout_bg"
Element shape doesn't have the required attribute android:layout_height
?
Element shape doesn't have the required attribute android:layout_height
La raison pour laquelle l'erreur a été affichée car layout_bg.xml n'était pas dans le dossier dessinable.
Pour API 21+, utilisez les vues de clip
Un découpage de contour arrondi a été ajouté à la View
classe dans l'API 21. Consultez ce document de formation ou cette référence pour plus d'informations.
Cette fonction intégrée rend les coins arrondis très faciles à mettre en œuvre. Il fonctionne sur n'importe quelle vue ou disposition et prend en charge un découpage approprié.
Voici ce qu'il faut faire:
android:background="@drawable/round_outline"
android:clipToOutline="true"
Malheureusement, il semble y avoir un bogue et cet attribut XML n'est actuellement pas reconnu. Heureusement, nous pouvons définir l'écrêtage en Java:
View.setClipToOutline(true)
À quoi il ressemble:
Note spéciale sur ImageViews
setClipToOutline()
ne fonctionne que lorsque l'arrière-plan de la vue est défini sur une forme dessinable. Si cette forme d'arrière-plan existe, View traite le contour de l'arrière-plan comme des bordures à des fins de découpe et d'observation.
Cela signifie que si vous souhaitez arrondir les coins d'une ImageView avec setClipToOutline()
, votre image doit provenir de la android:src
place de android:background
(puisque l'arrière-plan est utilisé pour la forme arrondie). Si vous DEVEZ utiliser l'arrière-plan pour définir votre image au lieu de src, vous pouvez utiliser cette solution de vues imbriquées:
src=@drawable...
au lieu de background=@drawable
? Vous pouvez le faire ou imbriquer votre ImageView dans une vue conteneur qui contient le contour de la forme.
Voici une copie d'un fichier XML pour créer un dessinable avec un fond blanc, une bordure noire et des coins arrondis:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffffff"/>
<stroke android:width="3dp"
android:color="#ff000000"
/>
<padding android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp"
/>
<corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
</shape>
enregistrez-le en tant que fichier xml dans le répertoire drawable, utilisez-le comme vous utiliseriez n'importe quel arrière-plan drawable (icône ou fichier de ressources) en utilisant son nom de ressource (R.drawable.your_xml_name)
<corners android:radius="7dp" />
:)
Utilisez CardView dans la bibliothèque de support Android v7. Bien qu'il soit un peu lourd, il résout tous les problèmes et assez facilement. Contrairement à la méthode d'arrière-plan configurable, elle peut réussir à découper les sous-vues.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="@android:color/transparent"
card_view:cardCornerRadius="5dp"
card_view:cardElevation="0dp"
card_view:contentPadding="0dp">
<YOUR_LINEARLAYOUT_HERE>
</android.support.v7.widget.CardView>
J'ai fait comme ça:
Vérifiez la capture d'écran:
Créez un fichier dessinable nommé avec custom_rectangle.xml
dans le dossier dessinable :
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@android:color/white" />
<corners android:radius="10dip" />
<stroke
android:width="1dp"
android:color="@android:color/white" />
</shape>
Appliquez maintenant l' arrière-plan du rectangle sur la vue :
mView.setBackground(R.drawlable.custom_rectangle);
Terminé
Je pense qu'une meilleure façon de le faire est de fusionner 2 choses:
faire une image bitmap de la mise en page, comme indiqué ici .
faire un arrondi dessinable à partir du bitmap, comme indiqué ici
définir le dessin sur une imageView.
Cela traitera les cas que d'autres solutions n'ont pas réussi à résoudre, tels que le contenu comportant des coins.
Je pense que c'est aussi un peu plus convivial pour le GPU, car il montre une seule couche au lieu de 2.
La seule meilleure façon est de créer une vue totalement personnalisée, mais cela représente beaucoup de code et peut prendre beaucoup de temps. Je pense que ce que j'ai suggéré ici est le meilleur des deux mondes.
Voici un extrait de la façon dont cela peut être fait:
RoundedCornersDrawable.java
/**
* shows a bitmap as if it had rounded corners. based on :
* http://rahulswackyworld.blogspot.co.il/2013/04/android-drawables-with-rounded_7.html
* easy alternative from support library: RoundedBitmapDrawableFactory.create( ...) ;
*/
public class RoundedCornersDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
public RoundedCornersDrawable(final Resources resources, final Bitmap bitmap, final float borderRadius) {
super(resources, bitmap);
bitmapShader = new BitmapShader(getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
final Bitmap b = getBitmap();
p = getPaint();
p.setAntiAlias(true);
p.setShader(bitmapShader);
final int w = b.getWidth(), h = b.getHeight();
rect = new RectF(0, 0, w, h);
this.borderRadius = borderRadius < 0 ? 0.15f * Math.min(w, h) : borderRadius;
}
@Override
public void draw(final Canvas canvas) {
canvas.drawRoundRect(rect, borderRadius, borderRadius, p);
}
}
CustomView.java
public class CustomView extends ImageView {
private View mMainContainer;
private boolean mIsDirty=false;
// TODO for each change of views/content, set mIsDirty to true and call invalidate
@Override
protected void onDraw(final Canvas canvas) {
if (mIsDirty) {
mIsDirty = false;
drawContent();
return;
}
super.onDraw(canvas);
}
/**
* draws the view's content to a bitmap. code based on :
* http://nadavfima.com/android-snippet-inflate-a-layout-draw-to-a-bitmap/
*/
public static Bitmap drawToBitmap(final View viewToDrawFrom, final int width, final int height) {
// Create a new bitmap and a new canvas using that bitmap
final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bmp);
viewToDrawFrom.setDrawingCacheEnabled(true);
// Supply measurements
viewToDrawFrom.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(canvas.getHeight(), MeasureSpec.EXACTLY));
// Apply the measures so the layout would resize before drawing.
viewToDrawFrom.layout(0, 0, viewToDrawFrom.getMeasuredWidth(), viewToDrawFrom.getMeasuredHeight());
// and now the bmp object will actually contain the requested layout
canvas.drawBitmap(viewToDrawFrom.getDrawingCache(), 0, 0, new Paint());
return bmp;
}
private void drawContent() {
if (getMeasuredWidth() <= 0 || getMeasuredHeight() <= 0)
return;
final Bitmap bitmap = drawToBitmap(mMainContainer, getMeasuredWidth(), getMeasuredHeight());
final RoundedCornersDrawable drawable = new RoundedCornersDrawable(getResources(), bitmap, 15);
setImageDrawable(drawable);
}
}
EDIT: a trouvé une alternative intéressante, basée sur la bibliothèque "RoundKornersLayouts" . Avoir une classe qui sera utilisée pour toutes les classes de mise en page que vous souhaitez étendre, à arrondir:
//based on https://github.com/JcMinarro/RoundKornerLayouts
class CanvasRounder(cornerRadius: Float, cornerStrokeColor: Int = 0, cornerStrokeWidth: Float = 0F) {
private val path = android.graphics.Path()
private lateinit var rectF: RectF
private var strokePaint: Paint?
var cornerRadius: Float = cornerRadius
set(value) {
field = value
resetPath()
}
init {
if (cornerStrokeWidth <= 0)
strokePaint = null
else {
strokePaint = Paint()
strokePaint!!.style = Paint.Style.STROKE
strokePaint!!.isAntiAlias = true
strokePaint!!.color = cornerStrokeColor
strokePaint!!.strokeWidth = cornerStrokeWidth
}
}
fun round(canvas: Canvas, drawFunction: (Canvas) -> Unit) {
val save = canvas.save()
canvas.clipPath(path)
drawFunction(canvas)
if (strokePaint != null)
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, strokePaint)
canvas.restoreToCount(save)
}
fun updateSize(currentWidth: Int, currentHeight: Int) {
rectF = android.graphics.RectF(0f, 0f, currentWidth.toFloat(), currentHeight.toFloat())
resetPath()
}
private fun resetPath() {
path.reset()
path.addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW)
path.close()
}
}
Ensuite, dans chacune de vos classes de mise en page personnalisées, ajoutez un code similaire à celui-ci:
class RoundedConstraintLayout : ConstraintLayout {
private lateinit var canvasRounder: CanvasRounder
constructor(context: Context) : super(context) {
init(context, null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs, 0)
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
init(context, attrs, defStyle)
}
private fun init(context: Context, attrs: AttributeSet?, defStyle: Int) {
val array = context.obtainStyledAttributes(attrs, R.styleable.RoundedCornersView, 0, 0)
val cornerRadius = array.getDimension(R.styleable.RoundedCornersView_corner_radius, 0f)
val cornerStrokeColor = array.getColor(R.styleable.RoundedCornersView_corner_stroke_color, 0)
val cornerStrokeWidth = array.getDimension(R.styleable.RoundedCornersView_corner_stroke_width, 0f)
array.recycle()
canvasRounder = CanvasRounder(cornerRadius,cornerStrokeColor,cornerStrokeWidth)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
setLayerType(FrameLayout.LAYER_TYPE_SOFTWARE, null)
}
}
override fun onSizeChanged(currentWidth: Int, currentHeight: Int, oldWidth: Int, oldheight: Int) {
super.onSizeChanged(currentWidth, currentHeight, oldWidth, oldheight)
canvasRounder.updateSize(currentWidth, currentHeight)
}
override fun draw(canvas: Canvas) = canvasRounder.round(canvas) { super.draw(canvas) }
override fun dispatchDraw(canvas: Canvas) = canvasRounder.round(canvas) { super.dispatchDraw(canvas) }
}
Si vous souhaitez prendre en charge les attributs, utilisez-les tels qu'ils sont écrits sur la bibliothèque:
<resources>
<declare-styleable name="RoundedCornersView">
<attr name="corner_radius" format="dimension"/>
<attr name="corner_stroke_width" format="dimension"/>
<attr name="corner_stroke_color" format="color"/>
</declare-styleable>
</resources>
Une autre alternative, qui pourrait être plus facile pour la plupart des utilisations: utilisez MaterialCardView. Il permet de personnaliser les coins arrondis, la couleur et la largeur du trait et l'élévation.
Exemple:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false"
tools:context=".MainActivity">
<com.google.android.material.card.MaterialCardView
android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center"
app:cardCornerRadius="8dp" app:cardElevation="8dp" app:strokeColor="#f00" app:strokeWidth="2dp">
<ImageView
android:layout_width="match_parent" android:layout_height="match_parent" android:background="#0f0"/>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>
Et le résultat:
Notez qu'il y a un léger problème d'artefacts sur les bords du trait (laisse quelques pixels du contenu là-bas), si vous l'utilisez. Vous pouvez le remarquer si vous zoomez. J'ai signalé ce problème ici .
EDIT: semble être corrigé, mais pas sur l'IDE. Rapporté ici .
Essaye ça...
1. créer du xml dessinable (custom_layout.xml):
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#FFFFFF" />
<stroke
android:width="2dp"
android:color="#FF785C" />
<corners android:radius="10dp" />
</shape>
2. ajoutez votre arrière-plan de vue
android:background="@drawable/custom_layout"
Si vous souhaitez arrondir votre mise en page, il est préférable d'utiliser le CardView, il a fourni de nombreuses fonctionnalités pour rendre le design magnifique.
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="@string/quote_code"
android:textColor="@color/white"
android:textSize="@dimen/text_head_size" />
</LinearLayout>
</android.support.v7.widget.CardView>
Avec cette card_view: cardCornerRadius = "5dp", vous pouvez changer le rayon.
La méthode la meilleure et la plus simple consisterait à utiliser card_background drawable dans votre mise en page. Cela suit également les directives de conception matérielle de Google. Incluez simplement ceci dans votre LinearLayout:
android:background="@drawable/card_background"
Ajoutez ceci à votre répertoire dessinable et nommez-le card_background.xml :
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#BDBDBD"/>
<corners android:radius="5dp"/>
</shape>
</item>
<item
android:left="0dp"
android:right="0dp"
android:top="0dp"
android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="#ffffff"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
Utilisez CardView pour obtenir des bords arrondis pour toutes les mises en page. Utilisez card_view: cardCornerRadius = "5dp" pour cardview pour obtenir des bords de mise en page arrondis.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="15dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="@string/quote_code"
android:textColor="@color/white"
android:textSize="@dimen/text_head_size" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".7"
android:text="@string/quote_details"
android:textColor="@color/white"
android:textSize="@dimen/text_head_size" />
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
Une meilleure façon de procéder serait:
background_activity.xml
<?xml version="1.0" encoding="UTF-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="fill">
<color android:color="@color/black"/>
</item>
<item>
<shape android:gravity="fill">
<solid android:color="@color/white"/>
<corners android:radius="10dip"/>
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
</shape>
</item>
</layer-list>
Cela fonctionnera également sous l'API 21 et vous donnera quelque chose comme ceci:
Si vous êtes prêt à faire un peu plus d'efforts pour un meilleur contrôle, utilisez-le android.support.v7.widget.CardView
avec son cardCornerRadius
attribut (et définissez l' elevation
attribut sur 0dp
pour vous débarrasser de toute ombre portée qui l'accompagne avec cardView). En outre, cela fonctionnera à partir du niveau API aussi bas que 15.
Fonction pour définir le rayon d'angle par programme
static void setCornerRadius(GradientDrawable drawable, float topLeft,
float topRight, float bottomRight, float bottomLeft) {
drawable.setCornerRadii(new float[] { topLeft, topLeft, topRight, topRight,
bottomRight, bottomRight, bottomLeft, bottomLeft });
}
static void setCornerRadius(GradientDrawable drawable, float radius) {
drawable.setCornerRadius(radius);
}
En utilisant
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.GREEN);
setCornerRadius(gradientDrawable, 20f);
//or setCornerRadius(gradientDrawable, 20f, 40f, 60f, 80f);
view.setBackground(gradientDrawable);
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF"/>
<stroke android:width="3dip" android:color="#B1BCBE" />
<corners android:radius="10dip"/>
<padding android:left="3dip" android:top="3dip" android:right="3dip" android:bottom="3dip" />
</shape>
@David, placez simplement la même valeur de remplissage que le trait pour que la bordure soit visible, quelle que soit la taille de l'image
J'ai pris la réponse de @gauravsapiens avec mes commentaires à l'intérieur pour vous donner une compréhension raisonnable de l'effet des paramètres.
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background color -->
<solid android:color="@color/white" />
<!-- Stroke around the background, width and color -->
<stroke android:width="4dp" android:color="@color/drop_shadow"/>
<!-- The corners of the shape -->
<corners android:radius="4dp"/>
<!-- Padding for the background, e.g the Text inside a TextView will be
located differently -->
<padding android:left="10dp" android:right="10dp"
android:bottom="10dp" android:top="10dp" />
</shape>
Si vous cherchez simplement à créer une forme qui arrondit les coins, supprimez le rembourrage et le trait fera l'affaire. Si vous supprimez également le solide, vous aurez en effet créé des coins arrondis sur un fond transparent.
Pour être paresseux, j'ai créé une forme en dessous, qui est juste un fond blanc uni avec des coins arrondis - profitez-en! :)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Background color -->
<solid android:color="@color/white" />
<!-- The corners of the shape -->
<corners android:radius="4dp"/>
</shape>
Créez votre xml en dessinable, layout_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="@color/your_colour" />
<stroke
android:width="2dp"
android:color="@color/your_colour" />
<corners android:radius="10dp" />
</shape>
<--width, color, radius should be as per your requirement-->
puis ajoutez ceci dans votre layout.xml
android:background="@drawable/layout_background"
Avec la bibliothèque de composants de matériaux, vous pouvez utiliser le MaterialShapeDrawable
pour dessiner des formes personnalisées .
Mettez simplement le LinearLayout dans votre mise en page XML:
<LinearLayout
android:id="@+id/linear_rounded"
android:layout_width="match_parent"
android:layout_height="wrap_content"
..>
<!-- content ..... -->
</LinearLayout>
Ensuite, dans votre code, vous pouvez appliquer un ShapeAppearanceModel
. Quelque chose comme:
float radius = getResources().getDimension(R.dimen.default_corner_radius);
LinearLayout linearLayout= findViewById(R.id.linear_rounded);
ShapeAppearanceModel shapeAppearanceModel = new ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius)
.build();
MaterialShapeDrawable shapeDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
//Fill the LinearLayout with your color
shapeDrawable.setFillColor(ContextCompat.getColorStateList(this,R.color.secondaryLightColor));
ViewCompat.setBackground(linearLayout,shapeDrawable);
Remarque: il nécessite la version 1.1.0 de la bibliothèque de composants matériels.
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="@dimen/_10sdp"
android:shape="rectangle">
<solid android:color="@color/header" />
<corners
android:bottomLeftRadius="@dimen/_5sdp"
android:bottomRightRadius="@dimen/_5sdp"
android:topLeftRadius="@dimen/_5sdp"
android:topRightRadius="@dimen/_5sdp" />