Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android P(9.0) 圆角失效 #37

Open
ZQ7 opened this issue Nov 12, 2018 · 19 comments
Open

Android P(9.0) 圆角失效 #37

ZQ7 opened this issue Nov 12, 2018 · 19 comments

Comments

@ZQ7
Copy link

ZQ7 commented Nov 12, 2018

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

@xiandanin
Copy link
Contributor

贴一下代码和截图

@ZQ7
Copy link
Author

ZQ7 commented Nov 15, 2018

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

@kxj0o
Copy link

kxj0o commented Nov 15, 2018

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

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

@GcsSloop
Copy link
Owner

谢谢反馈

@xiandanin
Copy link
Contributor

xiandanin commented Nov 16, 2018

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

@kxj0o
Copy link

kxj0o commented Nov 16, 2018

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

@GcsSloop GcsSloop changed the title 一加6内容显示空白 Android P(9.0) 圆角失效 Nov 20, 2018
@GcsSloop
Copy link
Owner

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

@ZQ7
Copy link
Author

ZQ7 commented Nov 21, 2018

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

@GcsSloop
Copy link
Owner

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

@summer0906
Copy link

summer0906 commented Nov 28, 2018

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

@summer0906
Copy link

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

@trycatchx
Copy link

trycatchx commented Mar 21, 2019

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

@Cand3h
Copy link

Cand3h commented Apr 13, 2019

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

@xiandanin
Copy link
Contributor

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

@Cand3h
Copy link

Cand3h commented Apr 13, 2019

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

@xiandanin
Copy link
Contributor

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

@HourInTheSun
Copy link

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

trycatchx commented May 7, 2019

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

@haydardsx
Copy link

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

管用,原理能解释下吗,看的有点绕。。

主要原因是安卓p把paint默认的xfermode改了,核心部分是

mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants