前言
最近项目中需要使用到圆角来展示内容。原先用得多的是用Canvas.clipXXX()或者是使用Paint.setXfermode(),现在用一个简单的方式就可实现,就是SDK21开始引入的ViewOutlineProvider类,用法也很简单。
ViewOutlineProvider
Interface by which a View builds its
Outline
, used for shadow casting and clipping.
从上面官网的说明可以了解到ViewOutlineProvider有两个作用:裁剪、阴影。
用法
利用裁剪实现圆角方法:
1 2 3 4 5 6 7 8 9 10 | ViewOutlineProvider outlineProvider = new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 30); //30为圆角半径,可自行修改 } }; View view = findViewById(R.id.view);//需要设置圆角的控件 view.setOutlineProvider(outlineProvider);//将ViewOutlineProvider设置给view view.setClipToOutline(true);//只有设置为true才能进行裁剪,false时不裁剪 |
可以看到只要3步即可实现:
- 创建ViewOutlineProvider,
- 实现
getOutline()
方法,使用Outline.setRoundRect()设置圆角矩阵,即裁剪后留下的有效区域 - 将ViewOutlineProvider设置给需要的View,并调用
View.setClipToOutline(true)
开启裁剪
当然也可以调用View.setClipToOutline(false)
关闭裁剪。
还有如下方法提供不同效果:
Outline.setOval()
Outline.setRect()
等……..
Outline类内部主要是有如下几个成员变量记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** @hide */ @Mode public int mMode = MODE_EMPTY; /** * Only guaranteed to be non-null when mode == MODE_CONVEX_PATH * * @hide */ public Path mPath; /** @hide */ public final Rect mRect = new Rect(); /** @hide */ public float mRadius = RADIUS_UNDEFINED; /** @hide */ public float mAlpha; |
利弊
利:使用方便
弊:必须要SDK>=21才能使用
SDK<21解决方式
SDK<21的这里提供一种,可直接使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | /** * 圆角的RelativeLayout,如需要其他布局的圆角,可直接修改继承的父类 */ public class RoundRectLayout extends RelativeLayout { //圆角裁剪范围 private Path mPath; //圆角半径 private int mRadius = 30; private int mWidth; private int mHeight; //是否开启圆角 private boolean mRoundMode = true; public RoundRectLayout(Context context) { super(context); init(); } public RoundRectLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; } private void init() { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) { setBackground(new ColorDrawable(0x33ff0000)); } else { setBackgroundDrawable(new ColorDrawable(0x33ff0000)); } mPath = new Path(); mPath.setFillType(Path.FillType.EVEN_ODD); } /** * 设置是否圆角裁边 * * @param roundMode */ public void setRoundMode(boolean roundMode) { mRoundMode = roundMode; invalidate(); } /** * 设置圆角半径 * * @param radius */ public void setCornerRadius(int radius) { mRadius = radius; invalidate(); } private void refreshRoundPath() { mPath.reset(); if (mRoundMode) { mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight), mRadius, mRadius, Path.Direction.CW); } } @Override public void draw(Canvas canvas) { if (mRoundMode) { int saveCount = canvas.save(); refreshRoundPath(); canvas.clipPath(mPath); super.draw(canvas); canvas.restoreToCount(saveCount); } else { super.draw(canvas); } } } |