如何在android中创建带圆角的视图

Zac*_*ach 74 android android-layout android-view android-shape

我试图在android中创建一个圆角边的视图.到目前为止我找到的解决方案是定义一个带圆角的形状,并将其用作该视图的背景.

这就是我所做的,定义一个drawable,如下所示

<padding
android:top="2dp"
android:bottom="2dp"/>
<corners android:bottomRightRadius="20dp"
android:bottomLeftRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp"/>
Run Code Online (Sandbox Code Playgroud)

现在我用它作为我的布局的背景如下

<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">
Run Code Online (Sandbox Code Playgroud)

这很好用,我可以看到视图有圆角.

但我的布局中有许多其他子视图说一个ImageView或一个MapView.当我在上面的布局中放置一个ImageView时,图像的角不会被剪裁/裁剪,而是显示为满.

我已经看到了其他解决方法,使它像这里解释的那样工作.

但有没有一种方法可以为视图设置圆角,并且所有子视图都包含在具有圆角的主视图中?

谢谢.

Jaa*_*tum 113

另一种方法是创建一个自定义布局类,如下所示.此布局首先将其内容绘制到屏幕外位图,使用圆角矩形屏蔽屏幕外位图,然后在实际画布上绘制屏幕外位图.

我尝试了它似乎工作(至少对我的简单测试用例).与常规布局相比,它当然会影响性能.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

像普通布局一样使用它:

<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>
Run Code Online (Sandbox Code Playgroud)

  • 我使用这种方法,工作正常.但是当我在布局中放置一个EditText时,屏幕在我输入时不会更新.当我关闭窗口时,文本会显示出来.关闭键盘后,屏幕会更新.有什么解决方法吗? (2认同)
  • 这不适用于使用占位符过渡(或实际上任何其他动画子项)的滑动库加载的图像.我有一个替代解决方案,但它要求你的背景颜色是纯色.请参阅https://gist.github.com/grennis/da9f86870c45f3b8ae00912edb72e868 (2认同)
  • 精细而有用的解决方案,但价格昂贵。仅包含六个图片的六个元素的RecyclerView无法平滑滚动。而且它并不取决于设备的功能(三星S9或Wileyfox Swift 2)。/sf/answers/2876908331/是更好的答案! (2认同)

roc*_*cer 54

或者您可以这样使用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>
Run Code Online (Sandbox Code Playgroud)

  • 一个缺点是它不支持<21 android api (5认同)

Vai*_*iya 42

shape.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>
Run Code Online (Sandbox Code Playgroud)

在你的布局里面

<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>
Run Code Online (Sandbox Code Playgroud)

  • @Zach:它以什么方式失效?当您询问原始问题时,与应用程序的工作方式相同? (3认同)
  • clipChildren没用,图像视图仍然在视图外部延伸. (2认同)
  • 我认为如果图像是矩形图像,这种方法将行不通,因为背景将绘制在图像内容的后面。这可能仅适用于具有透明度并且自身具有圆角的图像。 (2认同)

Sus*_*ant 17

如果在向布局添加触摸侦听器时遇到问题.将此布局用作父布局.

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


}
Run Code Online (Sandbox Code Playgroud)

<?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>
Run Code Online (Sandbox Code Playgroud)

  • 如果屏幕上没有太多动画,则效果很好,这会使屏幕一次又一次地绘制;从那以后,它将严重降低性能。应该尝试cardview,它具有有效的圆角方法(不使用剪切路径或canvas.drawRoundRect-在API 17以下无效,但使用porterFilterDuffColor) (2认同)

Don*_*key 16

Jaap van Hengstum的答案非常有用,但我觉得它很昂贵,如果我们将这个方法应用于Button,例如,由于视图呈现为位图,因此触摸效果会丢失.

对我来说,最好的方法和最简单的方法是在视图上应用蒙版,如下所示:

@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);
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是最正确的答案. (3认同)

Aja*_*pal 10

在drawable文件夹中创建一个xml round.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>
Run Code Online (Sandbox Code Playgroud)

然后使用round.xml作为项目的背景.然后它将给出圆角


iva*_*arz 9

在Android L中,您将能够使用View.setClipToOutline来获得该效果.在以前的版本中,无法仅以某种形状剪切随机ViewGroup的内容.

你将不得不考虑一些可以产生类似效果的东西:

  • 如果您只需要在ImageView中使用圆角,则可以使用着色器在您用作背景的形状上"绘制"图像.看一下这个库就可以了.

  • 如果你真的需要剪掉每个孩子,也许你可以对你的布局进行另一种观察?一个背景是你正在使用的颜色,中间是一个圆形的"洞"?实际上,您可以创建一个自定义ViewGroup,在覆盖onDraw方法的每个子项上绘制该形状.


Gab*_*tti 8

使用材料组件库制作View圆角的最佳方法是使用MaterialShapeDrawable.

创建一个带有自定义圆角的 ShapeAppearanceModel:

ShapeAppearanceModel shapeAppearanceModelLL1 = new ShapeAppearanceModel()
        .toBuilder()
        .setAllCorners(CornerFamily.ROUNDED,radius16)
        .build();
Run Code Online (Sandbox Code Playgroud)

创建一个MaterialShapeDrawable

MaterialShapeDrawable shapeDrawableLL1 = new MaterialShapeDrawable(shapeAppearanceModeLL1);
Run Code Online (Sandbox Code Playgroud)

如果您还想为深色主题应用高度覆盖,请使用以下命令:

MaterialShapeDrawable shapeDrawableLL1 = MaterialShapeDrawable.createWithElevationOverlay(this, 4.0f);
shapeDrawableLL1.setShapeAppearanceModel(shapeAppearanceModelLL1);
Run Code Online (Sandbox Code Playgroud)

可选:应用到 shapeDrawable 背景颜色和笔触

shapeDrawableLL1.setFillColor(
       ContextCompat.getColorStateList(this,R.color...));
 shapeDrawableLL1.setStrokeWidth(2.0f);
 shapeDrawableLL1.setStrokeColor(
       ContextCompat.getColorStateList(this,R.color...));
Run Code Online (Sandbox Code Playgroud)

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

LinearLayout linearLayout1= findViewById(R.id.ll_1);
ViewCompat.setBackground(linearLayout1,shapeDrawableLL1);
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

  • 应该是公认的答案。迄今为止最简单的解决方案! (2认同)

Llo*_*ter 7

CardView在 Android Studio 3.0.1 的 API 27 中为我工作。colorPrimary文件中引用了该文件res/values/colors.xml,这只是一个示例。对于其layout_width,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>
Run Code Online (Sandbox Code Playgroud)


Raj*_*kla 6

使用以下代码在 drawable 文件夹下创建一个 xml 文件。(我创建的文件名是rounded_corner.xml)

rounded_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>
Run Code Online (Sandbox Code Playgroud)

并保留此drawable作为background您要保留圆角边框的视图。让我们保留一段时间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>
Run Code Online (Sandbox Code Playgroud)


Rah*_*hul 5

你可以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>
Run Code Online (Sandbox Code Playgroud)

或者

形状.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>
Run Code Online (Sandbox Code Playgroud)

和你里面的布局

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

        ...

</LinearLayout>
Run Code Online (Sandbox Code Playgroud)


Tim*_*iev 5

如果你想圆一些特定的角落。

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
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 好答案!非常适合内部有多个视图的布局,并且我想将外部框做成圆形。 (2认同)