How to make a view with rounded corners?

I am trying to make a view in android with rounded edges. The solution I found so far is to define a shape with rounded corners and use it as the background of that view.

Here is what I did, define a drawable as given below:

<padding
android:top="2dp"
android:bottom="2dp"/>
<corners android:bottomRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp"/>

Now I used this as the background for my layout as below:

<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="@drawable/rounded_corner">

This works perfectly fine, I can see that the view has rounded edges.

But my layout has got many other child views in it, say an ImageView or a MapView. When I place an ImageView inside the above layout, the corners of image are not clipped/cropped, instead it appears full.

I have seen other workarounds to make it work like the one explained here.

But is there a method to set rounded corners for a view and all its child views are contained within that main view that has rounded corners?

160073 次浏览

The tutorial link you provided seems to suggest that you need to set the layout_width and layout_height properties, of your child elements to match_parent.

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent">

尝试这个属性与您的线性布局它将有所帮助
工具: context = “ . youractivity”

使用 xml 中的形状,并将底部或上部半径的属性设置为 want. ,然后将这个 xml 作为背景应用到您的视图中... ... 或者... ... 使用渐变从代码中实现这一点。

Xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">


<solid android:color="#f6eef1" />


<stroke
android:width="2dp"
android:color="#000000" />


<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />


<corners android:radius="5dp" />


</shape>

and inside you layout

<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:clipChildren="true"
android:background="@drawable/shape">


<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/your image"
android:background="@drawable/shape">


</LinearLayout>

在 Android L 中,你只需要使用 View.setClipToOutline就可以达到这个效果。在以前的版本中,没有办法只剪辑特定形状的随机 ViewGroup 的内容。

你将不得不想出一些可以给你类似效果的东西:

  • 如果你只需要在 ImageView 中使用圆角,你可以使用着色器在你用作背景的形状上“绘制”图像。以 这个图书馆为例。

  • 如果您真的需要裁剪每个孩子,也许您可以在您的布局的另一个视图?不管你用什么颜色的背景,中间有一个圆形的“洞”?实际上,您可以创建一个自定义 ViewGroup,在覆盖 onDraw 方法的每个子级上绘制该形状。

按照这个教程 以及它下面所有的讨论- Http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/

Guy Romain 是整个 Android 用户界面工具包的领先开发者之一,他在这篇文章中写道,制作一个圆角的容器(以及他所有的子视图)是可能的,但是他解释说这太昂贵了(从渲染问题的表现来看)。

我会建议你去根据他的职位,如果你想圆角,然后实施圆角 ImageView根据这个职位。然后,你可以把它放在任何背景的容器里,你会得到你想要的效果。

that's what I did also also eventually.

drawable文件夹中创建一个名为 round.xml的 xml 文件,并粘贴以下内容:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="#FFFFFF" />
<stroke android:width=".05dp" android:color="#d2d2d2" />
<corners android:topLeftRadius="5dp" android:topRightRadius="5dp" android:bottomRightRadius="5dp" android:bottomLeftRadius="5dp"/>
</shape>

then use the round.xml as background to any item. Then it will give you rounded corners.

另一种方法是创建一个像下面这样的自定义布局类。该布局首先将其内容绘制到离屏位图,然后用圆角矩形掩盖离屏位图,然后在实际画布上绘制离屏位图。

我试过了,它似乎起作用了(至少对我的简单测试案例是这样的)。与常规布局相比,它当然会影响性能。

package com.example;


import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.FrameLayout;


public class RoundedCornerLayout extends FrameLayout {
private final static float CORNER_RADIUS = 40.0f;


private Bitmap maskBitmap;
private Paint paint, maskPaint;
private float cornerRadius;


public RoundedCornerLayout(Context context) {
super(context);
init(context, null, 0);
}


public RoundedCornerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}


public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}


private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);


paint = new Paint(Paint.ANTI_ALIAS_FLAG);


maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));


setWillNotDraw(false);
}


@Override
public void draw(Canvas canvas) {
Bitmap offscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
Canvas offscreenCanvas = new Canvas(offscreenBitmap);


super.draw(offscreenCanvas);


if (maskBitmap == null) {
maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
}


offscreenCanvas.drawBitmap(maskBitmap, 0f, 0f, maskPaint);
canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint);
}


private Bitmap createMask(int width, int height) {
Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas(mask);


Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);


canvas.drawRect(0, 0, width, height, paint);


paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);


return mask;
}
}

像正常的布局一样使用它:

<com.example.RoundedCornerLayout
android:layout_width="200dp"
android:layout_height="200dp">


<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/test"/>


<View
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#ff0000"
/>


</com.example.RoundedCornerLayout>

与 Jaap van Hengstum 的答案不同:

  1. Use 位图着色器 instead of mask bitmap.
  2. 只创建一次位图。
public class RoundedFrameLayout extends FrameLayout {
private Bitmap mOffscreenBitmap;
private Canvas mOffscreenCanvas;
private BitmapShader mBitmapShader;
private Paint mPaint;
private RectF mRectF;


public RoundedFrameLayout(Context context) {
super(context);
init();
}


public RoundedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}


public RoundedFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}


private void init() {
setWillNotDraw(false);
}


@Override
public void draw(Canvas canvas) {
if (mOffscreenBitmap == null) {
mOffscreenBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888);
mOffscreenCanvas = new Canvas(mOffscreenBitmap);
mBitmapShader = new BitmapShader(mOffscreenBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setShader(mBitmapShader);
mRectF = new RectF(0f, 0f, canvas.getWidth(), canvas.getHeight());
}
super.draw(mOffscreenCanvas);


canvas.drawRoundRect(mRectF, 8, 8, mPaint);
}
}

If you are having problem while adding touch listeners to the layout. Use this layout as parent layout.

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.widget.FrameLayout;


public class RoundedCornerLayout extends FrameLayout {
private final static float CORNER_RADIUS = 6.0f;
private float cornerRadius;


public RoundedCornerLayout(Context context) {
super(context);
init(context, null, 0);
}


public RoundedCornerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}


public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}


private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}




@Override
protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();


final Path path = new Path();
path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), cornerRadius, cornerRadius, Path.Direction.CW);
canvas.clipPath(path, Region.Op.REPLACE);


canvas.clipPath(path);
super.dispatchDraw(canvas);
canvas.restoreToCount(count);
}




}

作为

<?xml version="1.0" encoding="utf-8"?>
<com.example.view.RoundedCornerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">


<RelativeLayout
android:id="@+id/patentItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingRight="20dp">
... your child goes here
</RelativeLayout>
</com.example.view.RoundedCornerLayout>
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {


Bitmap roundedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap
.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(roundedBitmap);


final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;


paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);


paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);


return roundedBitmap;
}

或者你可以像这样使用 android.support.v7.widget.CardView:

<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
card_view:cardBackgroundColor="@color/white"
card_view:cardCornerRadius="4dp">


<!--YOUR CONTENT-->
</android.support.v7.widget.CardView>
public class RoundedCornerLayout extends FrameLayout {
private double mCornerRadius;


public RoundedCornerLayout(Context context) {
this(context, null, 0);
}


public RoundedCornerLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}


public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}


private void init(Context context, AttributeSet attrs, int defStyle) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}


public double getCornerRadius() {
return mCornerRadius;
}


public void setCornerRadius(double cornerRadius) {
mCornerRadius = cornerRadius;
}


@Override
public void draw(Canvas canvas) {
int count = canvas.save();


final Path path = new Path();
path.addRoundRect(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), (float) mCornerRadius, (float) mCornerRadius, Path.Direction.CW);
canvas.clipPath(path, Region.Op.REPLACE);


canvas.clipPath(path);
super.draw(canvas);
canvas.restoreToCount(count);
}
}

Jaap van Hengstum's answer works great however I think it is expensive and if we apply this method on a Button for example, the touch effect is lost since the view is rendered as a bitmap.

For me the best method and the simplest one consists in applying a mask on the view, like that:

@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);


float cornerRadius = <whatever_you_want>;
this.path = new Path();
this.path.addRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, Path.Direction.CW);
}


@Override
protected void dispatchDraw(Canvas canvas) {
if (this.path != null) {
canvas.clipPath(this.path);
}
super.dispatchDraw(canvas);
}

CardView在 Android Studio 3.0.1的 API 27中为我工作。在 res/values/colors.xml文件中引用了 colorPrimary,它只是一个示例。对于布局宽度的 0dp,它将拉伸到父级的宽度。您必须根据需要配置约束和宽度/高度。

<android.support.v7.widget.CardView
android:id="@+id/cardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
app:cardBackgroundColor="@color/colorPrimary">


<!-- put your content here -->


</android.support.v7.widget.CardView>

使用以下代码在您的可绘制文件夹下创建一个 xml 文件

Round _ corner. xml

    <?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">


<!-- view background color -->
<solid
android:color="#a9c5ac" >
</solid>


<!-- view border color and width -->
<stroke
android:width="3dp"
android:color="#1c1b20" >
</stroke>


<!-- If you want to add some padding -->
<padding
android:left="4dp"
android:top="4dp"
android:right="4dp"
android:bottom="4dp"    >
</padding>


<!-- Here is the corner radius -->
<corners
android:radius="10dp"   >
</corners>
</shape>

And keep this drawable as background for the view to which you want to keep rounded corner border. Let’s keep it for a LinearLayout

    <LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/rounded_corner"
android:layout_centerInParent="true">


<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Hi, This layout has rounded corner borders ..."
android:gravity="center"
android:padding="5dp"/>


</LinearLayout>

你可以这样使用 androidx.cardview.widget.CardView:

<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/dimen_4"
app:cardElevation="@dimen/dimen_4"
app:contentPadding="@dimen/dimen_10">


...


</androidx.cardview.widget.CardView>

或者

Xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">


<solid android:color="#f6eef1" />


<stroke
android:width="2dp"
android:color="#000000" />


<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />


<corners android:radius="5dp" />


</shape>

在你的内部布局

<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape">


...


</LinearLayout>

与材料组件库的最佳方式,使 View与圆角是使用 MaterialShapeDrawable

创建一个自定义圆角的形状外观模型:

ShapeAppearanceModel shapeAppearanceModelLL1 = new ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius16)
.build();

创建一个 MaterialShapeDrawable:

MaterialShapeDrawable shapeDrawableLL1 = new MaterialShapeDrawable(shapeAppearanceModeLL1);

如果你想在黑色主题上也应用一个立面叠加,可以这样做:

MaterialShapeDrawable shapeDrawableLL1 = MaterialShapeDrawable.createWithElevationOverlay(this, 4.0f);
shapeDrawableLL1.setShapeAppearanceModel(shapeAppearanceModelLL1);

可选项: 应用于 shapeDrawable 的背景颜色和笔触

shapeDrawableLL1.setFillColor(
ContextCompat.getColorStateList(this,R.color...));
shapeDrawableLL1.setStrokeWidth(2.0f);
shapeDrawableLL1.setStrokeColor(
ContextCompat.getColorStateList(this,R.color...));

最后应用 shapeDrawable 作为 LinearLayout(或其他视图)的背景:

LinearLayout linearLayout1= findViewById(R.id.ll_1);
ViewCompat.setBackground(linearLayout1,shapeDrawableLL1);

enter image description here

要使用 com.google.android.Materials 创建圆角图像,材质: 1.2.0-beta01

 float radius = context.getResources().getDimension(R.dimen.border_radius_hug);
shapeAppearanceModel = new ShapeAppearanceModel()
.toBuilder()
.setAllCorners(CornerFamily.ROUNDED,radius)
.build();


imageView.setShapeAppearanceModel(shapeAppearanceModel)

或者如果您想在 xml 文件中使用它:

  <com.google.android.material.imageview.ShapeableImageView
android:id="@+id/thumb"
android:layout_width="80dp"
android:layout_height="60dp"
app:shapeAppearanceOverlay="@style/circleImageView"
/>

在 style.xml 中添加以下内容:

<style name="circleImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">10%</item>
</style>

In case you want to round some specific corner.

fun setCorners() {
        

val mOutlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {


val left = 0
val top = 0;
val right = view.width
val bottom = view.height
val cornerRadiusDP = 16f
val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, resources.displayMetrics).toInt()


// all corners
outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat())


/* top corners
outline.setRoundRect(left, top, right, bottom+cornerRadius, cornerRadius.toFloat())*/


/* bottom corners
outline.setRoundRect(left, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/


/* left corners
outline.setRoundRect(left, top, right + cornerRadius, bottom, cornerRadius.toFloat())*/


/* right corners
outline.setRoundRect(left - cornerRadius, top, right, bottom, cornerRadius.toFloat())*/


/* top left corner
outline.setRoundRect(left , top, right+ cornerRadius, bottom + cornerRadius, cornerRadius.toFloat())*/


/* top right corner
outline.setRoundRect(left - cornerRadius , top, right, bottom + cornerRadius, cornerRadius.toFloat())*/


/* bottom left corner
outline.setRoundRect(left, top - cornerRadius, right + cornerRadius, bottom, cornerRadius.toFloat())*/


/* bottom right corner
outline.setRoundRect(left - cornerRadius, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/


}
}


myView.apply {
outlineProvider = mOutlineProvider
clipToOutline = true
}
}


可以在线性布局中使用如下子元素:

enter image description here

回到这里:

enter image description here

我已经看到了许多解决方案,但大多数都是无用的图像 查看,除非您将“图像查看”更改为其他设计组件,我会这样做 不推荐它们,因为它们可能与某些 ** 使用:

** Width and color of stroke in drawable 和图片的空白处

这里是快速解决方案。 第一步:

<RelativeLayout
android:layout_width="90dp"
android:layout_height="90dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:scaleType="centerCrop"
android:src="@drawable/a" />


<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/card_helh" />


</RelativeLayout>

设计形状

第二步:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/_10dp"/>
<stroke android:color="@color/white" android:width="5dp"/>
</shape>

**

A note 关于设置夜间模式,设置颜色笔画颜色的颜色容器的夜间,使它看起来更均匀这 solution works 100% 这个解决方案是我的,我目前正在使用它