Comment puis-je faire une mise en page avec des coins arrondis? Je souhaite appliquer des angles arrondis à ma LinearLayout
.
1: Définir 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 de votre mise en page
Android:background="@drawable/layout_bg"
Pour API 21+, utilisez les vues de clip
Des contours arrondis ont été ajoutés à la classe View
de l'API 21. Voir ceci doc d'apprentissage ou this référence pour plus d'informations.
Cette fonctionnalité intégrée facilite la mise en œuvre des angles arrondis. 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 n bogue et cet attribut XML n'est actuellement pas reconnu. Heureusement, nous pouvons définir le découpage en Java:
View.setClipToOutline(true)
A quoi ça ressemble:
Remarque spéciale sur ImageViews
setClipToOutline()
ne fonctionne que lorsque l'arrière-plan de la vue est défini sur une forme pouvant être dessinée. Si cette forme d'arrière-plan existe, View considère le contour de l'arrière-plan comme des bordures à des fins de découpage et d'observation.
Cela signifie que si vous souhaitez arrondir les angles d'un ImageView avec setClipToOutline()
, votre image doit provenir de Android:src
au lieu de Android:background
(car 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 contournement des vues imbriquées:
Voici une copie d'un fichier XML pour créer un dessin 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 sous forme de fichier xml dans le répertoire pouvant être dessiné. Utilisez-le comme vous utiliseriez n'importe quel fond dessiné (icône ou fichier de ressources) en utilisant son nom de ressource (R.drawable.votre_nom_xml)
Utilisez CardView dans Android bibliothèque de support v7. Bien que ce soit un peu lourd, il résout tous les problèmes, et assez facilement. Contrairement à la méthode définie pour l’arrière-plan, elle peut découper les sous-vues avec succès.
<?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 pouvant être dessiné portant le nom custom_rectangle.xml
dans un dossier pouvant être dessiné :
<?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);
Fait
Je pense qu'une meilleure façon de le faire est de fusionner 2 choses:
faire un bitmap de la mise en page, comme indiqué ici .
faire un arrondi tirable de la bitmap, comme indiqué ici
définir le dessinable sur une imageView.
Cela permettra de gérer les cas que d'autres solutions n'ont pas réussi à résoudre, comme un contenu comportant des angles.
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 solution consiste à créer une vue totalement personnalisée, mais cela prend 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 de Nice, 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 supporter les attributs, utilisez ceci comme écrit dans 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, ainsi que l’altitude.
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 (y laisse quelques pixels du contenu), si vous l'utilisez. Vous pouvez le remarquer si vous effectuez un zoom avant. J'ai signalé ce problème ici .
EDIT: semble être corrigé, mais pas sur l'IDE. Signalé ici .
Essaye ça...
1.créer 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.add votre vue de fond
Android:background="@drawable/custom_layout"
Une meilleure façon de le faire 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 API 21 et vous donnera quelque chose comme ceci:
Si vous souhaitez faire un peu plus d'effort pour un meilleur contrôle, utilisez Android.support.v7.widget.CardView
avec son attribut cardCornerRadius
(et définissez l'attribut elevation
sur 0dp
pour vous en débarrasser. ombre portée avec le cardView). En outre, cela fonctionnera à partir du niveau 15 de l'API.
Si vous souhaitez rendre votre mise en page arrondie, il est préférable d’utiliser CardView, qui offre de nombreuses fonctionnalités pour rendre le design plus beau.
<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.
Utilisez CardView pour obtenir des bords arrondis pour n’importe quelle mise en page. Utilisez card_view: cardCornerRadius = "5dp" pour que cardview obtienne 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>
Fonction pour définir le rayon de coin par programmation
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, il suffit de mettre la même valeur de remplissage que le contour, pour que la bordure puisse être visible, taille de l'image sans égard
La méthode la plus simple et la meilleure consiste à utiliser card_background dessable dans votre mise en page. Cela suit également les directives de conception de matériaux 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>
Créez votre XML dans drawable, 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-->
et ensuite, ajoutez ceci dans votre layout.xml
Android:background="@drawable/layout_background"
J'ai pris @gauravsapiens répondre avec mes commentaires à l'intérieur pour vous donner une appréhension raisonnable de ce que les paramètres vont affecter.
<?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 souhaitez simplement créer une forme qui arrondit les angles, supprimez le rembourrage et le trait. Si vous supprimez également le solide, vous aurez effectivement créé des coins arrondis sur un fond transparent.
Par souci de paresse, j'ai créé une forme 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>
<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" />