如何使布局圆角..?

我如何制作圆角布局?我想给LinearLayout添加圆角。

678359 次浏览

1:在drawables中定义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"

下面是一个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>
将其保存为可绘制目录下的XML文件, 使用它就像使用任何可绘制的背景(图标或资源文件),使用它的资源名称(r.r able.your_xml_name)

我是这样做的:

检查屏幕截图:

相对布局背景

可拉的文件夹中创建名为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);

完成

我认为更好的方法是合并两件事:

  1. 制作布局的位图,如下所示here

  2. 从位图绘制一个可画图,如所示here

  3. 在imageView上设置drawable。

这将处理其他解决方案无法解决的情况,例如内容有角落。

我认为它对gpu更友好,因为它显示了一个单层而不是两层。

唯一更好的方法是创建一个完全自定义的视图,但这需要大量代码,可能会花费大量时间。我认为我在这里提出的建议是两全其美的。

以下是如何做到这一点的一小段:

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


}

编辑:发现了一个很好的替代方案,基于< >强" 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>

结果是:

enter image description here

请注意,如果您使用它,在笔画的边缘有一个轻微的工件问题(在那里留下一些内容像素)。放大就能看到。我已经报道过这个问题这里<强> < / >强

编辑:似乎是固定的,但不是在IDE。# EYZ0报道。

试试这个…

1.创建# EYZ0 (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,只是把padding的值和stroke一样,所以无论图像大小,边框都是可见的

对于API 21+,使用剪辑视图

圆角轮廓裁剪被添加到API 21中的View类中。更多信息请参见培训医生参考

这个内置的功能使圆角非常容易实现。它适用于任何视图或布局,并支持适当的剪辑。

下面是该怎么做:

    创建一个圆形的可绘制图形,并将其设置为视图的背景: 李# EYZ0 < / >
  • 剪辑大纲代码:setClipToOutline(true)

文档曾经说过您可以设置XML中的android:clipToOutline="true",但是这只虫子现在终于被解析了,文档现在正确地指出您只能在代码中这样做。

它的样子:

带和不带clipToOutline的示例

关于ImageViews的特别说明

setClipToOutline()仅在视图的背景设置为可绘制的形状时有效。如果此背景形状存在,视图将背景的轮廓作为剪切和阴影目的的边界。

这意味着如果你想在一个ImageView上用setClipToOutline()圆角,你的图像必须来自android:src而不是android:background(因为背景用于圆角形状)。如果你必须使用背景来设置你的图像而不是src,你可以使用这个嵌套视图的解决方案:

  • 创建一个外部布局,将其背景设置为可绘制的形状
  • 将布局包装在ImageView周围(没有填充)
  • ImageView(包括布局中的任何其他内容)现在将被剪切到外部布局的圆形形状。

最好和最简单的方法是在布局中使用card_background可绘制对象。这也符合谷歌的材料设计准则。只需要在你的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。 虽然它有点重,但它解决了所有的问题,而且足够简单。 不像set drawable background方法,它可以成功剪辑子视图
<?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获得任何布局的圆角边缘。 使用card_view: cardCornerRadius = " 5 dp” for cardview来获得圆角布局边缘
<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以下工作,并给你类似这样的东西:

Result


如果你愿意做一些更好的控制,然后使用android.support.v7.widget.CardView和它的cardCornerRadius属性(并将elevation属性设置为0dp,以摆脱任何伴随着cardView的阴影)。此外,这将从API水平低至15起工作。

在可绘制的layout_background.xml中创建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>

在材质组件库中,你可以使用<强> # EYZ0 < / >强绘制自定义形状

只要把线性布局放在你的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);

enter image description here

它需要材质组件库的版本1.1.0

步骤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>
你可以使用自定义视图,比如RoundAppBarRoundBottomAppBar。 在这里,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);

android圆角矩形形状

  • 前两个浮动用于左上角(其余对按顺时针方向对应)。

更多细节请阅读< >强这个答案< / >强