android如何给整个视图view圆角显示

关于如何给一个view设置圆角,有哪些方法呢?
1.给该view设置一个圆角的背景,这是最常见的用法。如以下代码:

round_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <corners android:radius="40dp" />
    <solid android:color="#33ff0000" />
</shape>

这是给view设置40dp的圆角

<android.support.v7.widget.RecyclerView
        android:id="@+id/rv_list_1"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_margin="20dp"
        android:background="@drawable/round_bg" />

效果如图:

这种方式,正常情况下是没有问题的,可是如果想实现无缝的圆角显示,例如,它里面的一个列表,紧贴着边缘,即padding为0,会发现,圆角的那部分区域,还是有子view在显示的,并没有完全的实现真正的圆角,因为只是外层的背景圆角了而已。
那有什么办法让子view也圆角显示呢?下面说下第二种方法。

2.通过代码设置圆角,如下:

/**
     * 设置视图裁剪的圆角半径
     * @param radius
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public static void setClipViewCornerRadius(View view, final int radius){

        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
            //不支持5.0版本以下的系统
            return;
        }

        if(view == null) return;

        if(radius <= 0){
            return;
        }

        /*view.setOutlineProvider(new ViewOutlineProvider() {

            @Override
            public void getOutline(View view, Outline outline) {
                outline.setRoundRect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom(), radius);
            }
        });*/
        view.setOutlineProvider(new ViewOutlineProvider() {

            @Override
            public void getOutline(View view, Outline outline) {
                outline.setRoundRect(0, 0, view.getWidth(),   view.getHeight(), radius);
            }
        });
        view.setClipToOutline(true);

    }

这是5.0版本之后新增的设置view边缘的方法,不支持5.0以下版本。

那有没更合适的方法呢,所幸,5.0版本之后,增加了新的组件,CardView,它可以设置圆角,阴影等。

<android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp"
        app:cardBackgroundColor="#33ff0000"
        app:cardCornerRadius="30dp">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_list_2"
            android:layout_width="150dp"
            android:layout_height="150dp" />
    </android.support.v7.widget.CardView>

CardView提供了兼容版本,当5.0版本以上时,子view被圆角了, 那么5.0版本以上时,支持吗?经测试是不支持的,但是系统给它增加padding时子 view完全显示在布局里面,不会超出圆角部分,算是适配的方法,这样比上一种方法,更加合适了一点。

那还有没有更好的方法,真正解决圆角view和里面的子view,并且兼容5.0以下版本呢?答案也是有的。我们知道View的绘图时有调用draw方法,绘图机制可参考http://blog.csdn.net/leehong2005/article/details/7307456

View#draw方法,提供了一个最基本的绘制机制,子类通常不需要重写这个方法。我们可以通过查看其源码,在View的draw里面,它通常需要做以下几件事情:

1,绘制自己的背景,如果有的话,因为背景始终都在最后面,所以要先画。

2,如果需要的话,保存canvas的layer来准备绘制渐变效果,比如说有alpha动画等。

3,绘制View的内容,其实就是调用onDraw方法,让子类可以绘制自己的内容。

4,绘制自己的child,具体怎么绘制孩子,ViewGroup会去重写相应的方法。基类的View只是把调用这绘制child的方法,当然这个方法在View里面,应该是什么都不做。

5,如果需要的话,画渐变效果并还原保存的canvas层。

6,绘制其他的元素,比如scrollbar等。

通常,View里面要做这些事情,而且顺序不能改变。
注意第4点,绘制子view的方法,这样的话,如果在绘制子view之前,要是给canvas设置圆角的path,是不是就可以呢。

/**
 * 圆角的RelativeLayout
 *
 */

public class RoundRectLayout extends RelativeLayout {

    private Path mPath;
    private int mRadius;

    private int mWidth;
    private int mHeight;
    private int mLastRadius;

    public static final int MODE_NONE = 0;
    public static final int MODE_ALL = 1;
    public static final int MODE_LEFT = 2;
    public static final int MODE_TOP = 3;
    public static final int MODE_RIGHT = 4;
    public static final int MODE_BOTTOM = 5;

    private int mRoundMode = MODE_ALL;

    public RoundRectLayout(Context context) {
        super(context);

        init();
    }

    public RoundRectLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();
    }

    private void init(){

        setBackgroundDrawable(new ColorDrawable(0x33ff0000));

        mPath = new Path();
        mPath.setFillType(Path.FillType.EVEN_ODD);

        setCornerRadius(ViewUtil.dp2px(getContext(), 30));
    }

    /**
     * 设置是否圆角裁边
     * @param roundMode
     */
    public void setRoundMode(int roundMode){
        mRoundMode = roundMode;
    }

    /**
     * 设置圆角半径
     * @param radius
     */
    public void setCornerRadius(int radius){
        mRadius = radius;
    }

    private void checkPathChanged(){

        if(getWidth() == mWidth && getHeight() == mHeight && mLastRadius == mRadius){
            return;
        }

        mWidth = getWidth();
        mHeight = getHeight();
        mLastRadius = mRadius;

        mPath.reset();

        switch (mRoundMode){
            case MODE_ALL:
                mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight), mRadius, mRadius, Path.Direction.CW);
                break;
            case MODE_LEFT:
                mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
                        new float[]{mRadius, mRadius, 0, 0, 0, 0, mRadius, mRadius},
                        Path.Direction.CW);
                break;
            case MODE_TOP:
                mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
                        new float[]{mRadius, mRadius, mRadius, mRadius, 0, 0, 0, 0},
                        Path.Direction.CW);
                break;
            case MODE_RIGHT:
                mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
                        new float[]{0, 0, mRadius, mRadius, mRadius, mRadius, 0, 0},
                        Path.Direction.CW);
                break;
            case MODE_BOTTOM:
                mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight),
                        new float[]{0, 0, 0, 0, mRadius, mRadius, mRadius, mRadius},
                        Path.Direction.CW);
                break;
        }

    }

    @Override
    public void draw(Canvas canvas) {

        if(mRoundMode != MODE_NONE){
            int saveCount = canvas.save();

            checkPathChanged();

            canvas.clipPath(mPath);
            super.draw(canvas);

            canvas.restoreToCount(saveCount);
        }else {
            super.draw(canvas);
        }


    }
}

这里,复写draw方法,在super.draw方法之前,给当前canvas设置path,这个path设置为圆角的方形。
然后在这个view包裹在自 view外,

<round.llh.com.roundtotalview.RoundRectLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="20dp">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_list_4"
            android:layout_width="150dp"
            android:layout_height="150dp" />
</round.llh.com.roundtotalview.RoundRectLayout>

这样经测试,5.0以上和以下版本效果都是可以的,当然消耗也是存在的,每次绘制之前,都要canvas.clipPath(mPath);,在复杂的view或者动画中,有可能不流畅,所有请谨慎使用。

以上四种方法各有利弊,大家可以选择自己合适的方式来实现圆角。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值