Android 如何创建圆角视图?

Android 如何创建圆角视图?,android,android-layout,view,android-view,android-shape,Android,Android Layout,View,Android View,Android Shape,我试图在android中创建一个具有圆形边缘的视图。到目前为止,我找到的解决方案是定义一个具有圆角的形状,并将其用作该视图的背景 下面是我所做的,定义一个可绘制的,如下所示: 现在我用它作为我的布局背景,如下所示: <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_c

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

下面是我所做的,定义一个可绘制的,如下所示:


现在我用它作为我的布局背景,如下所示:

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

这非常好,我可以看到视图有圆形的边缘

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

我已经看到了其他的解决办法,使它像一个解释

但是,有没有一种方法可以为视图及其所有视图设置圆角 子视图包含在已舍入的主视图中 角落


您提供的教程链接似乎建议您需要设置子元素的布局宽度和布局高度属性以匹配父元素

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

在线性布局中尝试此属性,它会有所帮助

工具:context=“.youractivity”

将xml中的形状与矩形一起使用。根据需要设置底部或上部半径的属性。然后将该xml作为背景应用于您的视图…或…使用渐变从代码中执行此操作。

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>
<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: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>
<LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/shape">

        ...

</LinearLayout>

在Android L中,您只需使用即可获得该效果。在以前的版本中,无法仅以特定形状剪裁随机视图组的内容

你必须想出一些能给你带来类似效果的方法:

  • 如果在ImageView中只需要圆角,则可以使用着色器在用作背景的形状上“绘制”图像。请看一个例子

  • 如果你真的需要剪辑每个孩子,也许你可以在你的布局上再看一眼?一个背景颜色是什么你正在使用,和一个圆形'洞'在中间?实际上,您可以创建一个自定义视图组,在覆盖onDraw方法的每个子对象上绘制该形状


遵循本教程及其下面的所有讨论-

根据盖伊·罗曼(Guy Romain)撰写的这篇文章,他是整个Android UI工具包的主要开发人员之一,可以制作一个圆角容器(及其所有子视图),但他解释说这太昂贵了(因为渲染问题的性能)

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


这也是我最终所做的。

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>


然后将
round.xml
作为
background
用于任何项目。然后,它将为您提供圆角。

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

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

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的答案不同:

  • 使用位图着色器而不是遮罩位图
  • 只创建一次位图
  • 公共类RoundedFrameLayout扩展了FrameLayout{
    私有位图mOffscreenBitmap;
    克里恩卡纳斯私人帆布;
    专用位图着色器mBitmapShader;
    私人油漆;
    私有RectF mRectF;
    公共圆形框架布局(上下文){
    超级(上下文);
    init();
    }
    公共RoundedFrameLayout(上下文、属性集属性){
    超级(上下文,attrs);
    init();
    }
    公共RoundedFrameLayout(上下文上下文、属性集属性、int-defStyleAttr){
    super(上下文、attrs、defStyleAttr);
    init();
    }
    私有void init(){
    setWillNotDraw(假);
    }
    @凌驾
    公共空白绘制(画布){
    if(mOffscreenBitmap==null){
    mOffscreenBitmap=Bitmap.createBitmap(canvas.getWidth()、canvas.getHeight()、Bitmap.Config.ARGB_8888);
    mOffscreenCanvas=新画布(mOffscreenBitmap);
    mBitmapShader=新位图着色器(mOffscreenBitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
    mPaint=新油漆(油漆.防油漆别名标志);
    mPaint.setShader(mBitmapShader);
    mRectF=newrectf(0f,0f,canvas.getWidth(),canvas.getHeight());
    }
    超级绘图(mOffscreenCanvas);
    canvas.drawRoundRect(mRectF,8,8,mPaint);
    }
    }
    
    如果在布局中添加触控监听器时出现问题。将此布局用作父布局

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

    
    ... 你的孩子到这里来了
    
    或者您可以使用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>
    
    <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>
    
    
    
    效果很好,但我认为这很昂贵,例如,如果我们在按钮上应用此方法,由于视图呈现为位图,因此触摸效果将丢失

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

    @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);
    }
    
    @覆盖
    已更改尺寸的受保护空心(int-width、int-height、int-oldWidth、int-oldHeight){
    super.onSizeChanged(宽度、高度、旧宽度、旧高度);
    浮动半径=;
    this.path=新路径();
    this.path.addRoundRect(新的RectF(0,0,宽度,高度),cornerRadius,cornerRadius,path.Direction.CW);
    }
    @超越
    
    @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);
    }
    
    <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 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>
    
        <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
    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>
    
    <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>
    
    ShapeAppearanceModel shapeAppearanceModelLL1 = new ShapeAppearanceModel()
            .toBuilder()
            .setAllCorners(CornerFamily.ROUNDED,radius16)
            .build();
    
    MaterialShapeDrawable shapeDrawableLL1 = new MaterialShapeDrawable(shapeAppearanceModeLL1);
    
    MaterialShapeDrawable shapeDrawableLL1 = MaterialShapeDrawable.createWithElevationOverlay(this, 4.0f);
    shapeDrawableLL1.setShapeAppearanceModel(shapeAppearanceModelLL1);
    
    shapeDrawableLL1.setFillColor(
           ContextCompat.getColorStateList(this,R.color...));
     shapeDrawableLL1.setStrokeWidth(2.0f);
     shapeDrawableLL1.setStrokeColor(
           ContextCompat.getColorStateList(this,R.color...));
    
    LinearLayout linearLayout1= findViewById(R.id.ll_1);
    ViewCompat.setBackground(linearLayout1,shapeDrawableLL1);
    
     float radius = context.getResources().getDimension(R.dimen.border_radius_hug);
        shapeAppearanceModel = new ShapeAppearanceModel()
                .toBuilder()
                .setAllCorners(CornerFamily.ROUNDED,radius)
                .build();
    
    imageView.setShapeAppearanceModel(shapeAppearanceModel)
    
      <com.google.android.material.imageview.ShapeableImageView
                android:id="@+id/thumb"
                android:layout_width="80dp"
                android:layout_height="60dp"
                app:shapeAppearanceOverlay="@style/circleImageView"
                />
    
    <style name="circleImageView" parent="">
          <item name="cornerFamily">rounded</item>
          <item name="cornerSize">10%</item>
    </style>
    
    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
            }
        }