android resource Como fazer layout com cantos arredondados..?




src android (13)

Como posso criar um layout com cantos arredondados? Eu quero aplicar cantos arredondados ao meu LinearLayout .


Tomei @gauravsapiens resposta com meus comentários dentro para dar-lhe uma apreensão razoável do que os parâmetros irão afetar.

<?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 você está apenas olhando para criar uma forma que arredonda os cantos, removendo o preenchimento e o traço fará. Se você também remover o sólido, terá criado cantos arredondados em um plano de fundo transparente.

Para ser preguiçoso, criei uma forma por baixo, que é apenas um fundo branco sólido com cantos arredondados - divirta-se! :)

<?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>

Eu fiz assim:

Verifique a captura de tela:

Crie um arquivo drawable chamado com custom_rectangle.xml na pasta 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>

Agora aplique o fundo do retângulo na visualização :

mView.setBackground(R.drawlable.custom_rectangle);

Feito


Eu acho que uma maneira melhor de fazer isso é mesclar duas coisas:

  1. faça um bitmap do layout, como mostrado here .

  2. faça um drawable arredondado do bitmap, como mostrado here

  3. defina o drawable em um imageView.

Isso tratará de casos que outras soluções não conseguiram resolver, como ter conteúdo com cantos.

Acho que também é um pouco mais compatível com GPU, já que mostra uma única camada em vez de 2.

A única maneira melhor é criar uma visualização totalmente personalizada, mas isso é muito código e pode levar muito tempo. Eu acho que o que eu sugeri aqui é o melhor dos dois mundos.

Aqui está um trecho de como isso pode ser feito:

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: encontrou uma boa alternativa, com base na biblioteca "RoundKornersLayouts" . Tenha uma classe que será usada para todas as classes de layout que você deseja estender, para serem arredondadas:

//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()
    }

}

Em seguida, em cada uma das suas classes de layout personalizadas, adicione um código semelhante a este:

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 você deseja dar suporte a atributos, use isso como está escrito na biblioteca:

<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>

Outra alternativa, que pode ser mais fácil para a maioria dos usos: use o MaterialCardView. Permite personalizar os cantos arredondados, cor e largura do traço e elevação.

Exemplo:

<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 o resultado:

Observe que há um pequeno problema de artefatos nas bordas do traço (deixa alguns pixels do conteúdo), se você usá-lo. Você pode notar se você aumentar o zoom. Eu relatei sobre esse problema here .


Create your 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-->

Finally in your layout.xml file write below line

 android:background="@drawable/layout_background"

<?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, basta colocar o mesmo valor de preenchimento como traço, para que a borda possa ser visível, tamanho da imagem sem importância


Aqui está uma cópia de um arquivo XML para criar um drawable com um fundo branco, borda preta e cantos arredondados:

 <?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>

salve-o como um arquivo xml no diretório drawable, use-o como se fosse usar qualquer segundo plano drawable (ícone ou arquivo de recurso) usando seu nome de recurso (R.drawable.your_xml_name)


Se você gostaria de fazer seu layout arredondado, é melhor usar o CardView, ele forneceu muitos recursos para tornar o design bonito.

<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>

Com este card_view: cardCornerRadius = "5dp", você pode mudar o raio.


Use CardView na biblioteca de suporte do Android v7. Embora seja um pouco pesado, resolve todos os problemas e é bastante fácil. Não é como o método de fundo drawable set, poderia clip subviews com sucesso.

<?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>

Uma maneira melhor de fazer isso seria:

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>

Isso funcionará abaixo da API 21 também e fornecerá algo assim:

Se você estiver disposto a fazer um pouco mais de controle, use android.support.v7.widget.CardView com seu atributo cardCornerRadius (e defina o atributo de elevation como 0dp para eliminar qualquer sombra adjacente com o cardView). Além disso, isso funcionará com um nível de API tão baixo quanto 15.


 <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" />


Função para definir raio de canto programaticamente

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);
}

Usando

GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.GREEN);
setCornerRadius(gradientDrawable, 20f);
//or setCornerRadius(gradientDrawable, 20f, 40f, 60f, 80f); 

view.setBackground(gradientDrawable);

Para API 21+, use exibições de clipe

O recorte do contorno arredondado foi adicionado à classe View na API 21. Consulte este documento de treinamento ou esta reference para obter mais informações.

Este recurso embutido torna os cantos arredondados muito fáceis de implementar. Ele funciona em qualquer visualização ou layout e suporta um recorte adequado.

Aqui está o que fazer:

  • Crie uma forma arredondada desenhável e defina-a como plano de fundo da sua visualização: android:background="@drawable/round_outline"
  • De acordo com a documentação, então tudo que você precisa fazer é isto: android:clipToOutline="true"

Infelizmente, parece haver um bug e esse atributo XML atualmente não é reconhecido. Felizmente, podemos definir o recorte em Java:

  • Em sua atividade ou fragmento: View.setClipToOutline(true)

O que isso parece:

Nota especial sobre o ImageViews

setClipToOutline() só funciona quando o plano de fundo da View é definido como uma forma de desenhar. Se essa forma de plano de fundo existir, o modo de exibição exibirá o contorno do plano de fundo como as bordas para fins de recorte e sombreamento.

Isso significa que, se você quiser arredondar os cantos em um ImageView com setClipToOutline() , sua imagem deve vir de android:src vez de android:background (já que o plano de fundo é usado para a forma arredondada). Se você DEVE usar o background para definir sua imagem em vez de src, você pode usar esta solução alternativa de views aninhadas:

  • Crie um layout externo com seu plano de fundo definido para sua forma drawable
  • Enrole esse layout em torno do seu ImageView (sem preenchimento)
  • O ImageView (incluindo qualquer outra coisa no layout) será agora recortado na forma arredondada do layout externo.

O melhor e mais simples método seria fazer uso de card_background drawable no seu layout. Isso também segue as diretrizes de design de material do Google. Apenas inclua isso em você LinearLayout:

android:background="@drawable/card_background"

Adicione isto ao seu diretório drawable e nomeie-o 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>






layout