rclayout icon indicating copy to clipboard operation
rclayout copied to clipboard

Android P(9.0) 圆角失效

Open ZQ7 opened this issue 6 years ago • 19 comments

RCRelativeLayout设置圆角后,View会填充为背景色

ZQ7 avatar Nov 12 '18 04:11 ZQ7

贴一下代码和截图

xiandanin avatar Nov 14 '18 09:11 xiandanin

代码: ` <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

ZQ7 avatar Nov 15 '18 07:11 ZQ7

Pixel 2 Android 9 圆角也会有问题 device-2018-11-15-200809

测试发现是Android 9系统以下的绘制发生了改变导致的 image 这是一个Android P的预期行为,请看google官方的回复https://issuetracker.google.com/issues/111819103

kxj0o avatar Nov 15 '18 12:11 kxj0o

谢谢反馈

GcsSloop avatar Nov 16 '18 01:11 GcsSloop

圆形和圆矩用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

xiandanin avatar Nov 16 '18 09:11 xiandanin

` 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在有些情况会有问题〜〜

kxj0o avatar Nov 16 '18 10:11 kxj0o

在 v1.8.0 版本修复了该问题。

GcsSloop avatar Nov 20 '18 09:11 GcsSloop

一加6(Android 9.0)设备问题依然存在

ZQ7 avatar Nov 21 '18 10:11 ZQ7

没有一加的设备,不知道一加是否自己修改了API的实现方式。

GcsSloop avatar Nov 22 '18 01:11 GcsSloop

小米MIX2S(Android 9.0)还是有问题, 会出现RCRelativeLayout被背景色填充 不使用剪裁背景没有问题, 使用剪裁背景就会导致整个View被背景色填充

summer0906 avatar Nov 28 '18 08:11 summer0906

如果把硬件加速关了, 可能会出现如下的报错, 导致整个View不显示, 变成透明 view not displayed because it is too large to fit into a software layer

summer0906 avatar Nov 28 '18 10:11 summer0906

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

trycatchx avatar Mar 21 '19 10:03 trycatchx

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

Cand3h avatar Apr 13 '19 16:04 Cand3h

9.0的兼容之前修复了的 用最新版即可 2da96e0 Android P (9.0) 圆角失效问题

xiandanin avatar Apr 13 '19 16:04 xiandanin

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 avatar Apr 13 '19 17:04 Cand3h

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

xiandanin avatar Apr 15 '19 06:04 xiandanin

@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 avatar May 07 '19 10:05 HourInTheSun

@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 的问题
    }

trycatchx avatar May 07 '19 10:05 trycatchx