Come posso creare un layout con angoli arrotondati? Voglio applicare angoli arrotondati al mio LinearLayout
.
Come posso creare un layout con angoli arrotondati? Voglio applicare angoli arrotondati al mio LinearLayout
.
Risposte:
1: Definisci layout_bg.xml in drawable:
<?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: aggiungi layout_bg.xml
come sfondo al layout
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
Il motivo per cui l'errore è stato mostrato perché layout_bg.xml non era all'interno della cartella di disegno.
Per API 21+, utilizzare le visualizzazioni di clip
Il ritaglio del contorno arrotondato è stato aggiunto alla View
classe nell'API 21. Vedi questo documento di formazione o questo riferimento per ulteriori informazioni.
Questa funzione integrata semplifica l'implementazione degli angoli arrotondati. Funziona su qualsiasi vista o layout e supporta il ritaglio corretto.
Ecco cosa fare:
android:background="@drawable/round_outline"
android:clipToOutline="true"
Sfortunatamente, sembra che ci sia un bug e questo attributo XML attualmente non è riconosciuto. Fortunatamente, possiamo impostare il ritaglio in Java:
View.setClipToOutline(true)
Cosa sembra:
Nota speciale su ImageViews
setClipToOutline()
funziona solo quando lo sfondo della vista è impostato su una forma tracciabile. Se esiste questa forma di sfondo, Visualizza considera il contorno dello sfondo come bordi per scopi di ritaglio e ombreggiatura.
Ciò significa che se si desidera arrotondare gli angoli di ImageView con setClipToOutline()
, l'immagine deve provenire android:src
invece da android:background
(poiché lo sfondo viene utilizzato per la forma arrotondata). Se DEVI utilizzare lo sfondo per impostare l'immagine anziché src, puoi usare questa soluzione alternativa per le visualizzazioni nidificate:
src=@drawable...
invece di background=@drawable
? Puoi farlo o annidare ImageView all'interno di una vista contenitore che contiene il contorno della forma.
Ecco una copia di un file XML per creare un disegno con uno sfondo bianco, bordo nero e angoli arrotondati:
<?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>
salvalo come file XML nella directory di disegno, usalo come se usassi qualsiasi sfondo di disegno (icona o file di risorse) usando il suo nome di risorsa (R.drawable.your_xml_name)
<corners android:radius="7dp" />
:)
Usa CardView nella libreria di supporto di Android v7. Sebbene sia un po 'pesante, risolve tutti i problemi e abbastanza facile. Non come il metodo di sfondo disegnabile impostato, potrebbe tagliare correttamente le sottoview.
<?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>
Ho fatto così:
Vedi screenshot:
Crea file drawable chiamato con custom_rectangle.xml
nella cartella drawable :
<?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>
Ora applica lo sfondo Rettangolo su Visualizza :
mView.setBackground(R.drawlable.custom_rectangle);
Fatto
Penso che un modo migliore per farlo sia unire 2 cose:
crea una bitmap del layout, come mostrato qui .
crea un disegno arrotondato dalla bitmap, come mostrato qui
imposta il disegno su un imageView.
Questo gestirà i casi che altre soluzioni non sono riuscite a risolvere, come ad esempio avere contenuti con angoli.
Penso che sia anche un po 'più compatibile con la GPU, in quanto mostra un singolo strato invece di 2.
L'unico modo migliore è creare una vista totalmente personalizzata, ma è un sacco di codice e potrebbe richiedere molto tempo. Penso che ciò che ho suggerito qui sia il migliore dei due mondi.
Ecco un frammento di come può essere fatto:
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: trovato una bella alternativa, basata sulla libreria "RoundKornersLayouts" . Avere una classe che verrà utilizzata per tutte le classi di layout che si desidera estendere, da arrotondare:
//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()
}
}
Quindi, in ciascuna delle tue classi di layout personalizzate, aggiungi il codice simile a questo:
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) }
}
Se desideri supportare gli attributi, usa questo come scritto sulla libreria:
<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>
Un'altra alternativa, che potrebbe essere più semplice per la maggior parte degli usi: utilizzare MaterialCardView. Permette di personalizzare gli angoli arrotondati, il colore e la larghezza del tratto e l'elevazione.
Esempio:
<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>
E il risultato:
Nota che c'è un leggero problema di artefatti ai bordi del tratto (lascia alcuni pixel del contenuto lì), se lo usi. Puoi notarlo se ingrandisci. Ho segnalato questo problema qui .
EDIT: sembra essere stato corretto, ma non sull'IDE. Segnalato qui .
Prova questo...
1.Creare xml disegnabile (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.aggiungi lo sfondo della vista
android:background="@drawable/custom_layout"
Se desideri arrotondare il layout, è meglio usare CardView, che ha fornito molte funzionalità per rendere bello il design.
<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>
Con questo card_view: cardCornerRadius = "5dp", puoi cambiare il raggio.
Il metodo migliore e più semplice sarebbe quello di utilizzare il card_background disegnabile nel tuo layout. Ciò segue anche le linee guida per la progettazione dei materiali di Google. Includi questo in te LinearLayout:
android:background="@drawable/card_background"
Aggiungi questo alla tua directory disegnabile e chiamalo 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>
Usa CardView per ottenere bordi arrotondati per qualsiasi layout. Usa card_view: cardCornerRadius = "5dp" per cardview per ottenere bordi arrotondati del layout.
<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>
Un modo migliore per farlo sarebbe:
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>
Funzionerà anche sotto API 21 e ti darà qualcosa del genere:
Se sei disposto a fare un po 'più di sforzo un controllo migliore, quindi usa il android.support.v7.widget.CardView
suo cardCornerRadius
attributo (e imposta l' elevation
attributo su 0dp
per sbarazzarti di qualsiasi ombra che lo accompagna con CardView). Inoltre, funzionerà dal livello API a partire da 15.
Funzione per impostare il raggio d'angolo programmaticamente
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);
}
utilizzando
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, inserisci semplicemente lo stesso valore dell'imbottitura del tratto, in modo che il bordo possa essere visibile, dimensioni dell'immagine senza riguardo
Ho preso la risposta di @gauravsapiens con i miei commenti all'interno per darti una ragionevole comprensione di quali effetti avranno i parametri.
<?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>
Se stai solo cercando di creare una forma che arrotonda gli angoli, rimuoverà l'imbottitura e il tratto. Se rimuovete anche il solido, avrete effettivamente creato degli angoli arrotondati su uno sfondo trasparente.
Per essere pigro ho creato una forma sottostante, che è solo uno sfondo bianco solido con angoli arrotondati - divertiti! :)
<?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>
Crea il tuo XML in 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-->
e poi aggiungilo nel tuo layout.xml
android:background="@drawable/layout_background"
Con la Libreria dei componenti materiali è possibile utilizzare MaterialShapeDrawable
per disegnare forme personalizzate .
Basta inserire LinearLayout nel layout XML:
<LinearLayout
android:id="@+id/linear_rounded"
android:layout_width="match_parent"
android:layout_height="wrap_content"
..>
<!-- content ..... -->
</LinearLayout>
Quindi nel tuo codice puoi applicare a ShapeAppearanceModel
. Qualcosa di simile a:
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);
Nota :: richiede la versione 1.1.0 della libreria dei componenti del materiale.
<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" />