Isso não funciona. como você definiu, é o plano de fundo; portanto, o conteúdo substitui os cantos arredondados e, se você tiver um conteúdo desenhado nos cantos, não os verá arredondados.
desenvolvedor Android
22
Quase sempre, meu conteúdo nunca cobre os cantos. Isso funciona perfeitamente.
David JY Tang
2
Como você evita o erro Element shape doesn't have the required attribute android:layout_height?
Lorenz
2
Element shape doesn't have the required attribute android:layout_heightO motivo pelo qual o erro foi mostrado porque layout_bg.xml não estava dentro da pasta desenhável.
Atul
8
@ nhouser9: na verdade, é mais como "Funciona, mas esteja avisado de que o seu primeiro plano / conteúdo pode aparecer nos cantos". Portanto, dependendo do caso de uso, pode funcionar 100%. Fico feliz que a resposta não tenha tantas votações negativas porque é útil, e fico feliz que o comentário tenha cem votações positivas porque é fácil identificar a limitação com esta solução. Melhor dos dois mundos.
Benoit Duffez 01/01
125
Para a API 21 ou superior, use as visualizações de clipe
O recorte de contorno arredondado foi adicionado à Viewclasse na API 21. Consulte este documento de treinamento ou esta referência para obter mais informações.
Esse recurso incorporado facilita a implementação de cantos arredondados. Funciona em qualquer visualização ou layout e suporta recorte adequado.
Aqui está o que fazer:
Crie uma gaveta de forma arredondada e defina-a como o plano de fundo da sua exibição:
android:background="@drawable/round_outline"
De acordo com a documentação, tudo o que você precisa fazer é o seguinte: android:clipToOutline="true"
Infelizmente, parece haver um bug e esse atributo XML atualmente não é reconhecido. Felizmente, podemos definir o recorte em Java:
Na 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 vista é definido como uma forma desenhável. Se essa forma de plano de fundo existir, o View tratará o contorno do plano de fundo como bordas para fins de recorte e sombreamento.
Isso significa que, se você deseja arredondar os cantos em um ImageView setClipToOutline(), sua imagem deve ser originada em android:srcvez de android:background(já que o fundo é usado para a forma arredondada). Se você DEVE usar o plano de fundo para definir sua imagem em vez de src, pode usar esta solução alternativa de visualizações aninhadas:
Crie um layout externo com o plano de fundo definido como sua forma desenhável
Enrole esse layout em torno do seu ImageView (sem preenchimento)
O ImageView (incluindo qualquer outra coisa no layout) agora será cortado na forma arredondada do layout externo.
Não funciona em API inferior a 21. Não posso esperar até que eu só posso apoiar API 21.
startoftext
O uso de 'setClipToOutline' funciona, mas também remove o próprio quadro (o drawable que você usa para o fundo). Existe alguma maneira de evitar isso?
desenvolvedor android
Você leu minha nota sobre o uso em src=@drawable...vez de background=@drawable? Você pode fazer isso ou aninhar seu ImageView dentro de uma exibição de contêiner que contém o contorno da forma.
hungryghost
9
Todo mundo comenta esse bug - ele tem quase três anos e não mostra sinais de conserto a qualquer momento nesta década. Vamos pressionar um pouco.
Josh Hansen
Como não esse bug ser ainda fixo
P Fuster
74
Aqui está uma cópia de um arquivo XML para criar um drawable com fundo branco, borda preta e cantos arredondados:
salve-o como um arquivo xml no diretório drawable. Use-o como se fosse qualquer plano de fundo drawable (ícone ou arquivo de recurso) usando seu nome de recurso (R.drawable.your_xml_name)
Adorava a possibilidade de arredondar cantos específicos
Mercury
1
Esta resposta é praticamente a resposta acima. A única mudança real aqui é a definição de cada raio de canto, e dada a sua o mesmo valor para cada canto eu teria escrito em uma linha em vez disso: <corners android:radius="7dp" />:)
ZooMagic
esta é a melhor resposta para mim, uma vez que abrange a disponibilidade de arredondamento cantos específicos ... bom trabalho, funciona 100%
Mahmoud Ayman
Os cantos do ImageView não são arredondados (cortados), como resolvo isso?
Primož Kralj
Ainda funciona em setembro de 2019. Bom.
Nikolas Rieble 19/09/19
36
Use o CardView na biblioteca de suporte do Android v7. Embora seja um pouco pesado, resolve todos os problemas e é fácil. Não como o método de segundo plano desenhável, ele pode cortar subvisões com êxito.
Muito melhor para todos que podem "pagar" do que qualquer outra coisa. Confunde-me que uma coisa tão básica não é parte de vistas padrão do Android, sendo um grampo em CSS para quase qualquer navegador web
Ben Philipp
29
Eu fiz assim:
Verificar captura de tela:
Crie um arquivo drawable nomeado com custom_rectangle.xmlna pasta drawable :
Isso não funciona. como você definiu, é o plano de fundo; portanto, o conteúdo substitui os cantos arredondados e, se você tiver um conteúdo desenhado nos cantos, não os verá arredondados.
desenvolvedor android
25
Eu acho que a melhor maneira de fazer isso é mesclar duas coisas:
faça um drawable arredondado do bitmap, como mostrado aqui
defina o drawable em um imageView.
Isso resolverá casos que outras soluções não conseguiram resolver, como conteúdo com cantos.
Eu acho que também é um pouco mais amigável à GPU, pois mostra uma única camada em vez de 2.
A única maneira melhor é fazer uma visualização totalmente personalizada, mas isso é muito código e pode levar muito tempo. Eu acho que o que 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 ser arredondada:
//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 código semelhante a este:
Outra alternativa, que pode ser mais fácil para a maioria dos usos: use MaterialCardView. Permite personalizar os cantos arredondados, a cor e a largura do traço e a elevação.
Observe que há um pequeno problema de artefato nas bordas do traçado (deixa alguns pixels do conteúdo), se você o usar. Você pode perceber se aumentar o zoom. Eu relatei sobre esse problema aqui .
EDIT: parece estar corrigido, mas não no IDE. Relatado aqui .
Graças para a montagem de esta resposta incrível, ele tem me movendo na direção certa, mas eu poderia usar alguma ajuda com um problema muito relacionada aqui stackoverflow.com/questions/25877515/...
Will Thomson
Isso gera erro, pois não há construtor padrão disponível no ImageView.
Anuj
Essa resposta deve ser aceita. Em vez de lógica plana, você desceu e encontrou uma solução incrível. Isso também resolve os problemas mencionados nos comentários para outras respostas. Obrigado pelo seu esforço e talvez você possa corrigir uma classe totalmente funcional e compartilhá-la via github. Eu acho que isso pode ajudar muitas pessoas.
Arda Kara
@ Senhor Você acha que eu deveria? Eu vou pensar sobre isso. Por enquanto, você pode ver os outros repositórios que eu criei
desenvolvedor android
Como grande parte disso, você pode experimentá-lo. Btw autofittextview parece muito legal.
Assim como escrevi acima sobre uma solução semelhante: Isso não funciona. como você definiu, é o plano de fundo; portanto, o conteúdo substitui os cantos arredondados e, se você tiver um conteúdo desenhado nos cantos, não os verá arredondados.
desenvolvedor android
9
Se você deseja arredondar o layout, é melhor usar o CardView, pois ele oferece muitos recursos para deixar o design bonito.
O melhor e mais simples método seria usar o card_background drawable em seu layout. Isso também segue as diretrizes de design de material do Google. Basta incluir isso no seu LinearLayout:
android:background="@drawable/card_background"
Adicione isso ao seu diretório drawable e chame -o de card_background.xml :
Use o CardView para obter bordas arredondadas para qualquer layout. Use card_view: cardCornerRadius = "5dp" para cardview obter bordas de layout arredondadas.
Isso também funcionará abaixo da API 21 e fornecerá algo assim:
Se você estiver disposto a fazer um pouco mais de esforço para ter um controle melhor, use-o android.support.v7.widget.CardViewcom seu cardCornerRadiusatributo (e defina o elevationatributo 0dppara se livrar de qualquer sombra que acompanha o cardView). Além disso, isso funcionará no nível da API tão baixo quanto 15.
Se o conteúdo se encaixar no plano de fundo, ele será substituído. Ele realmente não se encaixa na forma que você definiu.
desenvolvedor android
Você quer dizer outra visão? Você pode atualizar o código para mostrar o que você quer dizer? A idéia é que os cantos arredondados não colocariam área preta. Nos cantos, deve haver cores transparentes.
desenvolvedor android
Oh, eu recebo sua pergunta agora. Eu acho que para isso, você pode se contentar com uma pequena margem fixa sobre o seu conteúdo
Abdul Wasae
Mas, então, o conteúdo não será cortado na forma que você escolher, porque as margens fixas são retangulares e não de acordo com a forma que você escolher.
Eu levei a resposta @gauravsapiens com meus comentários para dentro para lhe dar uma compreensão razoável do efeito dos parâmetros.
<?xml version="1.0" encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android"><!-- Background color --><solidandroid:color="@color/white"/><!-- Stroke around the background, width and color --><strokeandroid:width="4dp"android:color="@color/drop_shadow"/><!-- The corners of the shape --><cornersandroid:radius="4dp"/><!-- Padding for the background, e.g the Text inside a TextView will be
located differently --><paddingandroid:left="10dp"android:right="10dp"android:bottom="10dp"android:top="10dp"/></shape>
Se você está apenas procurando criar uma forma que contorne os cantos, remover o preenchimento e o traço serve. Se você também remover o sólido, criará cantos arredondados em um fundo transparente.
Por uma questão de 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"?><shapexmlns:android="http://schemas.android.com/apk/res/android"><!-- Background color --><solidandroid:color="@color/white"/><!-- The corners of the shape --><cornersandroid:radius="4dp"/></shape>
<?xml version="1.0" encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android"><solidandroid:color="@color/your_colour"/><strokeandroid:width="2dp"android:color="@color/your_colour"/><cornersandroid:radius="10dp"/></shape>
<--width, color, radius should be as per your requirement-->
Em seguida, no seu código, você pode aplicar a ShapeAppearanceModel. Algo como:
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 :: requer a versão 1.1.0 da biblioteca de componentes do material.
Respostas:
1: Defina layout_bg.xml nos drawables:
2: adicione
layout_bg.xml
como plano de fundo ao seu layoutfonte
Element shape doesn't have the required attribute android:layout_height
?Element shape doesn't have the required attribute android:layout_height
O motivo pelo qual o erro foi mostrado porque layout_bg.xml não estava dentro da pasta desenhável.Para a API 21 ou superior, use as visualizações de clipe
O recorte de contorno arredondado foi adicionado à
View
classe na API 21. Consulte este documento de treinamento ou esta referência para obter mais informações.Esse recurso incorporado facilita a implementação de cantos arredondados. Funciona em qualquer visualização ou layout e suporta recorte adequado.
Aqui está o que fazer:
android:background="@drawable/round_outline"
android:clipToOutline="true"
Infelizmente, parece haver um bug e esse atributo XML atualmente não é reconhecido. Felizmente, podemos definir o recorte em Java:
View.setClipToOutline(true)
O que isso parece:
Nota especial sobre o ImageViews
setClipToOutline()
só funciona quando o plano de fundo da vista é definido como uma forma desenhável. Se essa forma de plano de fundo existir, o View tratará o contorno do plano de fundo como bordas para fins de recorte e sombreamento.Isso significa que, se você deseja arredondar os cantos em um ImageView
setClipToOutline()
, sua imagem deve ser originada emandroid:src
vez deandroid:background
(já que o fundo é usado para a forma arredondada). Se você DEVE usar o plano de fundo para definir sua imagem em vez de src, pode usar esta solução alternativa de visualizações aninhadas:fonte
src=@drawable...
vez debackground=@drawable
? Você pode fazer isso ou aninhar seu ImageView dentro de uma exibição de contêiner que contém o contorno da forma.Aqui está uma cópia de um arquivo XML para criar um drawable com fundo branco, borda preta e cantos arredondados:
salve-o como um arquivo xml no diretório drawable. Use-o como se fosse qualquer plano de fundo drawable (ícone ou arquivo de recurso) usando seu nome de recurso (R.drawable.your_xml_name)
fonte
<corners android:radius="7dp" />
:)Use o CardView na biblioteca de suporte do Android v7. Embora seja um pouco pesado, resolve todos os problemas e é fácil. Não como o método de segundo plano desenhável, ele pode cortar subvisões com êxito.
fonte
Eu fiz assim:
Verificar captura de tela:
Crie um arquivo drawable nomeado com
custom_rectangle.xml
na pasta drawable :Agora aplique o plano de fundo do retângulo no modo de exibição :
Feito
fonte
Eu acho que a melhor maneira de fazer isso é mesclar duas coisas:
faça um bitmap do layout, como mostrado aqui .
faça um drawable arredondado do bitmap, como mostrado aqui
defina o drawable em um imageView.
Isso resolverá casos que outras soluções não conseguiram resolver, como conteúdo com cantos.
Eu acho que também é um pouco mais amigável à GPU, pois mostra uma única camada em vez de 2.
A única maneira melhor é fazer uma visualização totalmente personalizada, mas isso é muito código e pode levar muito tempo. Eu acho que o que sugeri aqui é o melhor dos dois mundos.
Aqui está um trecho de como isso pode ser feito:
RoundedCornersDrawable.java
CustomView.java
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 ser arredondada:
Em seguida, em cada uma das suas classes de layout personalizadas, adicione código semelhante a este:
Se você deseja suportar atributos, use isto como está escrito na biblioteca:
Outra alternativa, que pode ser mais fácil para a maioria dos usos: use MaterialCardView. Permite personalizar os cantos arredondados, a cor e a largura do traço e a elevação.
Exemplo:
E o resultado:
Observe que há um pequeno problema de artefato nas bordas do traçado (deixa alguns pixels do conteúdo), se você o usar. Você pode perceber se aumentar o zoom. Eu relatei sobre esse problema aqui .
EDIT: parece estar corrigido, mas não no IDE. Relatado aqui .
fonte
Tente isso ...
1.criar xml desenhável (custom_layout.xml):
2. adicione o seu plano de exibição
fonte
Se você deseja arredondar o layout, é melhor usar o CardView, pois ele oferece muitos recursos para deixar o design bonito.
Com este card_view: cardCornerRadius = "5dp", você pode alterar o raio.
fonte
O melhor e mais simples método seria usar o card_background drawable em seu layout. Isso também segue as diretrizes de design de material do Google. Basta incluir isso no seu LinearLayout:
Adicione isso ao seu diretório drawable e chame -o de card_background.xml :
fonte
Use o CardView para obter bordas arredondadas para qualquer layout. Use card_view: cardCornerRadius = "5dp" para cardview obter bordas de layout arredondadas.
fonte
Uma maneira melhor de fazer isso seria:
background_activity.xml
Isso também funcionará abaixo da API 21 e fornecerá algo assim:
Se você estiver disposto a fazer um pouco mais de esforço para ter um controle melhor, use-o
android.support.v7.widget.CardView
com seucardCornerRadius
atributo (e defina oelevation
atributo0dp
para se livrar de qualquer sombra que acompanha o cardView). Além disso, isso funcionará no nível da API tão baixo quanto 15.fonte
Função para o raio do canto programado
Usando
fonte
@ David, basta colocar preenchimento com o mesmo valor que o traçado, para que a borda fique visível, sem tamanho de imagem
fonte
Eu levei a resposta @gauravsapiens com meus comentários para dentro para lhe dar uma compreensão razoável do efeito dos parâmetros.
Se você está apenas procurando criar uma forma que contorne os cantos, remover o preenchimento e o traço serve. Se você também remover o sólido, criará cantos arredondados em um fundo transparente.
Por uma questão de ser preguiçoso, criei uma forma por baixo, que é apenas um fundo branco sólido com cantos arredondados - divirta-se! :)
fonte
Crie seu xml no drawable,
layout_background.xml
e depois adicione isso no seu
layout.xml
fonte
Com a Biblioteca de componentes de material, você pode usar o
MaterialShapeDrawable
para desenhar formas personalizadas .Basta colocar o LinearLayout no seu layout xml:
Em seguida, no seu código, você pode aplicar a
ShapeAppearanceModel
. Algo como:Nota :: requer a versão 1.1.0 da biblioteca de componentes do material.
fonte
fonte