Android 如何制作带有圆角的视图?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26074784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:58:36  来源:igfitidea点击:

How to make a view with rounded corners?

androidandroid-layoutviewandroid-viewandroid-shape

提问by Zach

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.

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

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

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

<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 ImageViewinside the above layout, the corners of image are not clipped/cropped, instead it appears full.

但是我的布局中有许多其他子视图,比如 ImageView 或MapView. 当我ImageView在上面的布局中放置一个时,图像的角没有被剪裁/裁剪,而是看起来很饱满。

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?

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

回答by Jaap van Hengstum

Another approach is to make a custom layout class like the one below. This layout first draws its contents to an offscreen bitmap, masks the offscreen bitmap with a rounded rect and then draws the offscreen bitmap on the actual canvas.

另一种方法是制作一个像下面这样的自定义布局类。此布局首先将其内容绘制到屏幕外位图,使用圆角矩形遮罩屏幕外位图,然后在实际画布上绘制屏幕外位图。

I tried it and it seems to work (at least for my simple testcase). It will of course affect performance compared to a regular layout.

我试过了,它似乎有效(至少对于我的简单测试用例)。与常规布局相比,它当然会影响性能。

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

Use this like a normal layout:

像正常布局一样使用它:

<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>

回答by rocketspacer

Or you can use a android.support.v7.widget.CardViewlike so:

或者你可以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>

回答by Vaishali Sutariya

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>

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>

回答by Donkey

Jaap van Hengstum's answerworks 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.

Jaap van Hengstum 的回答效果很好,但我认为它很昂贵,例如,如果我们在 Button 上应用此方法,则由于视图呈现为位图,因此触摸效果会丢失。

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

回答by Sushant

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


}

as

作为

<?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>

回答by Ajay Venugopal

Create a xml file called round.xmlin the drawablefolder and paste this content:

round.xmldrawable文件夹中创建一个 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.xmlas backgroundto any item. Then it will give you rounded corners.

然后将round.xmlasbackground用于任何项目。然后它会给你圆角。

回答by ivagarz

In Android L you will be able to just use View.setClipToOutlineto get that effect. In previous versions there is no way to just clip the contents of a random ViewGroup in a certain shape.

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

You will have to think of something that would give you a similar effect:

您将不得不考虑一些会给您带来类似效果的东西:

  • If you only need rounded corners in the ImageView, you can use a shader to 'paint' the image over the shape you are using as background. Take a look at this libraryfor an example.

  • If you really need every children to be clipped, maybe you can another view over your layout? One with a background of whatever color you are using, and a round 'hole' in the middle? You could actually create a custom ViewGroup that draws that shape over every children overriding the onDraw method.

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

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

回答by Tal Kanel

follow this tutorial and all the discussion beneath it- http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/

遵循本教程及其下面的所有讨论- http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/

according to this post written by Guy Romain, one of the leading developers of the entire Android UI toolkit, it is possible to make a container (and all his child views) with rounded corners, but he explained that it too expensive (from performances of rendering issues).

根据整个 Android UI 工具包的主要开发人员之一 Guy Romain 撰写的这篇文章,可以制作带有圆角的容器(以及他所有的子视图),但他解释说它太昂贵了(从性能来看)渲染问题)。

I'll recommend you to go according to his post, and if you want rounded corners, then implement rounded corners ImageViewaccording to this post. then, you could place it inside a container with any background, and you'll get the affect you wish.

我会建议你按照他的帖子去,如果你想要圆角,那么ImageView根据这个帖子实现圆角。然后,你可以把它放在任何背景的容器中,你就会得到你想要的效果。

that's what I did also also eventually.

这也是我最终所做的。

回答by Lloyd Rochester

The CardViewworked for me in API 27 in Android Studio 3.0.1. The colorPrimarywas referenced in the res/values/colors.xmlfile and is just an example. For the layout_width of 0dpit will stretch to the width of the parent. You'll have to configure the constraints and width/height to your needs.

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

<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>

回答by Rajneesh Shukla

Create a xml file under your drawable folder with following code. (The name of the file I created is rounded_corner.xml)

使用以下代码在 drawable 文件夹下创建一个 xml 文件。(我创建的文件名是rounded_corner.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>

And keep this drawableas backgroundfor the view to which you want to keep rounded corner border. Let's keep it for a LinearLayout

并保留此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>