rclayout
rclayout copied to clipboard
Android P(9.0) 圆角失效
RCRelativeLayout设置圆角后,View会填充为背景色
贴一下代码和截图
代码: ` <com.hulu.commonres.view.rclayout.RCRelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" app:clip_background="true" app:round_corner_top_left="@dimen/public_corner_radius_9" app:round_corner_top_right="@dimen/public_corner_radius_9">
......
</com.hulu.commonres.view.rclayout.RCRelativeLayout>`
问题: 在一加6(Android 9.0)设备上View会被背景色填充
原因:
public void draw(Canvas canvas) { mRCHelper.refreshRegion(this); if (mRCHelper.mClipBackground) { canvas.save(); canvas.clipPath(mRCHelper.mClipPath); super.draw(canvas); canvas.restore(); } else { super.draw(canvas); } }
canvas.clipPath()和硬件加速引起
关闭硬件加速可以解决问题,是否有其他解决方案 关闭硬件加速参考https://github.com/GcsSloop/AndroidNote/issues/7
Pixel 2 Android 9 圆角也会有问题
测试发现是Android 9系统以下的绘制发生了改变导致的
这是一个Android P的预期行为,请看google官方的回复https://issuetracker.google.com/issues/111819103
谢谢反馈
圆形和圆矩用ViewOutlineProvider倒是一个好的替代方案,单个角要角度好像不行,setConvexPath没有效果
/**
* Returns whether the outline can be used to clip a View.
* <p>
* Currently, only Outlines that can be represented as a rectangle, circle,
* or round rect support clipping.
*
* @see android.view.View#setClipToOutline(boolean)
*/
public boolean canClip() {
return mMode != MODE_CONVEX_PATH;
}
https://developer.android.google.cn/reference/android/graphics/Outline.html#canClip() https://issuetracker.google.com/issues/37064491
` public void onClipDraw(Canvas canvas) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { onClipDrawLessApi28(canvas); } else { onClipDrawGreaterOrEqualApi28(canvas); } }
private void onClipDrawLessApi28(Canvas canvas) {
if (mStrokeWidth > 0) {
// 支持半透明描边,将与描边区域重叠的内容裁剪掉
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(mStrokeWidth * 2);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mClipPath, mPaint);
// 绘制描边
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
mPaint.setColor(mStrokeColor);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mClipPath, mPaint);
}
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(mClipPath, mPaint);
}
private void onClipDrawGreaterOrEqualApi28(Canvas canvas) {
if (mStrokeWidth > 0) {
mPaint.setColor(mStrokeColor);
mPaint.setStrokeWidth(mStrokeWidth * 2);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mClipPath, mPaint);
}
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
if (!mClipPath.isInverseFillType()) {
mClipPath.toggleInverseFillType();
}
canvas.drawPath(mClipPath, mPaint);
mPaint.setXfermode(null);
mClipPath.toggleInverseFillType();
}`
我兼容了一下Android P 不过RCImageView在有些情况会有问题〜〜
在 v1.8.0 版本修复了该问题。
一加6(Android 9.0)设备问题依然存在
没有一加的设备,不知道一加是否自己修改了API的实现方式。
小米MIX2S(Android 9.0)还是有问题, 会出现RCRelativeLayout被背景色填充 不使用剪裁背景没有问题, 使用剪裁背景就会导致整个View被背景色填充
如果把硬件加速关了, 可能会出现如下的报错, 导致整个View不显示, 变成透明 view not displayed because it is too large to fit into a software layer
@summer0906 我已经解决了,看下我的代码。在小米 mi8 (9.0) ,运行得很好!
@Override
public void draw(Canvas canvas) {
if (mRCHelper.mClipBackground) {
canvas.saveLayer(mRCHelper.mLayer, null, Canvas.ALL_SAVE_FLAG);
super.draw(canvas);
clipLayout(canvas);
canvas.restore();
} else {
super.draw(canvas);
}
}
private void clipLayout(Canvas canvas) {
Paint mPaint = new Paint();
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.FILL);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawPath(mRCHelper.mClipPath, mPaint);
} else {
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
final Path path = new Path();
path.addRect(0, 0, (int) mRCHelper.mLayer.width(), (int) mRCHelper.mLayer.height(), Path.Direction.CW);
path.op(mRCHelper.mClipPath, Path.Op.DIFFERENCE);
canvas.drawPath(path, mPaint);
}
}
@summer0906 我已经解决了,看下我的代码。在小米 mi8 (9.0) ,运行得很好!
@Override public void draw(Canvas canvas) { if (mRCHelper.mClipBackground) { canvas.saveLayer(mRCHelper.mLayer, null, Canvas.ALL_SAVE_FLAG); super.draw(canvas); clipLayout(canvas); canvas.restore(); } else { super.draw(canvas); } } private void clipLayout(Canvas canvas) { Paint mPaint = new Paint(); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL); if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) { mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawPath(mRCHelper.mClipPath, mPaint); } else { mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); final Path path = new Path(); path.addRect(0, 0, (int) mRCHelper.mLayer.width(), (int) mRCHelper.mLayer.height(), Path.Direction.CW); path.op(mRCHelper.mClipPath, Path.Op.DIFFERENCE); canvas.drawPath(path, mPaint); } }
Where did you put this code? (I have the same problem on Moto G6)
9.0的兼容之前修复了的 用最新版即可 2da96e0 Android P (9.0) 圆角失效问题
9.0 compatibility was fixed before using the latest version 2da96e0 Android P (9.0) fillet invalidation problem
I've got v1.8.1 and using "com.gcssloop.widget.RCRelativeLayout". Problem occurs on my Moto G6 where background color appears in foreground and not in background (Views in RelativeLayout are not shown as the background color is overlaying them).
@Cand3h I don't have this problem with the 9.0 device I have, so there is no way to reproduce your problem.
If you set the background in the internal layout, can you solve your problem?
<com.gcssloop.widget.RCRelativeLayout
android:layout_width="100dp"
android:layout_height="100dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<!--content-->
...
</RelativeLayout>
</com.gcssloop.widget.RCRelativeLayout>
@summer0906 我已经解决了,看下我的代码。在小米 mi8 (9.0) ,运行得很好!
@Override public void draw(Canvas canvas) { if (mRCHelper.mClipBackground) { canvas.saveLayer(mRCHelper.mLayer, null, Canvas.ALL_SAVE_FLAG); super.draw(canvas); clipLayout(canvas); canvas.restore(); } else { super.draw(canvas); } } private void clipLayout(Canvas canvas) { Paint mPaint = new Paint(); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL); if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) { mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawPath(mRCHelper.mClipPath, mPaint); } else { mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); final Path path = new Path(); path.addRect(0, 0, (int) mRCHelper.mLayer.width(), (int) mRCHelper.mLayer.height(), Path.Direction.CW); path.op(mRCHelper.mClipPath, Path.Op.DIFFERENCE); canvas.drawPath(path, mPaint); } }
管用,原理能解释下吗,看的有点绕。。
@HourInTheSun
原理就是对整个布局的 背景 切一下。
还有另外一个的解决方法,看下面代码:
public RCRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRCHelper = new RCHelper();
mRCHelper.initAttrs(context, attrs);
setLayerType(View.LAYER_TYPE_HARDWARE, null); //加入硬件加速,可解决9.0 的问题
}