提问人:Addy 提问时间:4/23/2013 最后编辑:Gabriele MariottiAddy 更新时间:4/15/2022 访问量:717605
如何制作圆角布局..?
How to make layout with rounded corners..?
答:
1:在可绘制对象中定义layout_bg.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="3dp" android:color="#B1BCBE" />
<corners android:radius="10dp"/>
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
</shape>
2:将背景添加到布局中layout_bg.xml
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
显示错误的原因layout_bg.xml因为 不在可绘制文件夹中。
下面是一个 XML 文件的副本,用于创建具有白色背景、黑色边框和圆角的可绘制对象:
<?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>
将其保存为 drawable 目录中的 xml 文件, 使用它就像使用任何可绘制背景(图标或资源文件)一样使用它,使用其资源名称 (R.drawable.your_xml_name)
评论
<corners android:radius="7dp" />
我是这样做的:
检查屏幕截图:
在 drawable 文件夹中创建名为 的 drawable 文件:custom_rectangle.xml
<?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>
现在在视图上应用矩形背景:
mView.setBackground(R.drawlable.custom_rectangle);
做
评论
我认为更好的方法是合并两件事:
这将处理其他解决方案无法解决的情况,例如内容有角落。
我认为它对 GPU 也更友好一些,因为它显示的是单层而不是 2 层。
唯一更好的方法是制作一个完全自定义的视图,但这需要大量的代码,并且可能需要很多时间。我认为我在这里的建议是两全其美的。
以下是如何完成的片段:
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);
}
}
自定义视图:.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);
}
}
编辑:找到了一个不错的替代方案,基于“RoundKornersLayouts”库。有一个类,该类将用于要扩展的所有布局类,并进行舍入:
//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()
}
}
然后,在每个自定义布局类中,添加类似于以下内容的代码:
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) }
}
如果您希望支持属性,请使用库上写的以下内容:
<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>
另一种选择,对于大多数用途来说可能更容易: 使用 MaterialCardView 。它允许自定义圆角、描边颜色和宽度以及高度。
例:
<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>
结果:
请注意,如果您使用它,则在描边的边缘存在轻微的伪影问题(在那里留下内容的一些像素)。如果你放大,你可以注意到它。我已经在这里报告了这个问题。
编辑:似乎已修复,但不在IDE上。在这里报告。
评论
试试这个...
1.创建可绘制的XML(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.添加视图背景
android:background="@drawable/custom_layout"
评论
<?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,只需将填充值与描边相同,因此无论图像大小如何,边框都可见
对于 API 21+,请使用剪辑视图
在 API 21 中,已将圆角轮廓剪裁添加到类中。有关详细信息,请参阅此培训文档或此参考。View
这种内置功能使圆角非常容易实现。它适用于任何视图或布局,并支持适当的剪辑。
这是要做的事情:
- 创建一个可绘制的圆角形状,并将其设置为视图的背景:
android:background="@drawable/round_outline"
- 剪辑以在代码中概述:
setClipToOutline(true)
文档曾经说过您可以设置 XML,但这个错误现在终于解决了,文档现在正确地指出您只能在代码中执行此操作。android:clipToOutline="true"
它看起来像什么:
关于 ImageView 的特别说明
setClipToOutline()
仅当视图的背景设置为可绘制的形状时才有效。如果存在此背景形状,则“视图”会将背景的轮廓视为用于剪裁和阴影的边框。
这意味着,如果要使用 ,则图像必须来自而不是 (因为 background 用于圆角形状)。如果必须使用 background 而不是 src 来设置图像,则可以使用以下嵌套视图解决方法:setClipToOutline()
android:src
android:background
- 创建一个外部布局,其背景设置为可绘制的形状
- 将该布局环绕在 ImageView 周围(不带填充)
- ImageView(包括布局中的任何其他内容)现在将被裁剪到外部布局的圆角形状。
评论
src=@drawable...
background=@drawable
最好和最简单的方法是在布局中使用card_background可绘制对象。这也遵循了 Google 的材料设计指南。只需将其包含在 LinearLayout 中即可:
android:background="@drawable/card_background"
将它添加到您的可绘制目录中,并将其命名为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>
在 android v7 支持库中使用 CardView。 虽然它有点重,但它解决了所有问题,而且很容易。 与设置可绘制背景方法不同,它可以成功剪辑子视图。
<?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>
评论
使用 CardView 获取任何布局的圆角边缘。 对 cardview 使用 card_view:cardCornerRadius=“5dp” 来获取圆角布局边缘。
<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>
评论
如果你想使你的布局四舍五入,最好使用CardView,它提供了许多功能来使设计美观。
<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>
使用此 card_view:cardCornerRadius=“5dp”,您可以更改半径。
更好的方法是:
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>
这也将在 API 21 以下工作,并为您提供如下内容:
如果您愿意付出更多的努力,更好地控制,那么请与其属性一起使用(并将属性设置为以摆脱 cardView 附带的任何投影)。此外,这将在低至 15 的 API 级别下工作。android.support.v7.widget.CardView
cardCornerRadius
elevation
0dp
评论
在 drawable 中创建您的 xml,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-->
然后,将其添加到您的layout.xml
android:background="@drawable/layout_background"
<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" />
以编程方式设置拐角半径的功能
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);
}
用
GradientDrawable gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(Color.GREEN);
setCornerRadius(gradientDrawable, 20f);
//or setCornerRadius(gradientDrawable, 20f, 40f, 60f, 80f);
view.setBackground(gradientDrawable);
我已经用我的评论@gauravsapiens答案,让您合理地了解参数将产生什么影响。
<?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>
如果您只是想创建一个圆角的形状,那么去除填充和笔触就可以了。如果同时删除实体,则实际上会在透明背景上创建圆角。
为了懒惰,我在下面创建了一个形状,它只是一个带有圆角的纯白色背景 - 尽情享受吧!:)
<?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>
通过材质组件库,您可以使用 MaterialShapeDrawable
绘制自定义形状。
只需将 LinearLayout 放在 xml 布局中:
<LinearLayout
android:id="@+id/linear_rounded"
android:layout_width="match_parent"
android:layout_height="wrap_content"
..>
<!-- content ..... -->
</LinearLayout>
然后,在代码中,您可以应用 .像这样:ShapeAppearanceModel
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);
注意::它需要 1.1.0 版本的材料组件库。
评论
clipToOutline=true
第 1 步:在 drawables 文件夹中定义bg_layout.xml,并将以下代码放入其中。
第 2 步:将该bg_layout.xml作为背景添加到您的布局中,完成。
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#EEEEEE"/> <!--your desired colour for solid-->
<stroke
android:width="3dp"
android:color="#EEEEEE" /> <!--your desired colour for border-->
<corners
android:radius="50dp"/> <!--shape rounded value-->
</shape>
您可以使用自定义视图来执行此操作,例如 RoundAppBar 和 RoundBottomAppBar。
这里 a 用于画布。path
clipPath
我来晚了一点,但这仍然是一个问题。因此,我编写了一组用于数据绑定的 OutlineProviders 和 BindingAdapters,使您能够从 xml 中剪切角。
注意:带轮廓的剪裁不支持不同尺寸的角!
我在这个 stackoverflow 帖子上用代码写了一个详细的回复
您将通过代码 + 绑定适配器获得什么:
<androidx.constraintlayout.widget.ConstraintLayout
clipRadius="@{@dimen/some_radius}"
clipBottomLeft="@{@dimen/some_radius}"
clipBottomRight="@{@dimen/some_radius}"
clipTopLeft="@{@dimen/some_radius}"
clipTopRight="@{@dimen/some_radius}"
clipCircle="@{@bool/clip}"
这使您能够将视图裁剪为圆形、所有角、一个方向(左、上、右、下)或单角的圆角。
评论
如果您想要的只是一个简单的圆角矩形,请长话短说。
float r=8;
ShapeDrawable shape =
new ShapeDrawable (new RoundRectShape(new float[] { r, r, r, r, r, r, r, r },null,null));
shape.getPaint().setColor(Color.RED);
view.setBackground(shape);
- 前两个浮点数用于左上角(其余对应顺时针对应)。
有关更多详细信息,请阅读此答案
评论