3

On the left is screenshot taken on Android P beta and on right is on Android 26. Curve differences There seems to be inconsistencies on how Xfermode is working on Android P beta.

Below is the corresponding code.

public class CropView extends View {

    private Paint paint;
    private Path clipPath;
    private int arcHeight;

    public CropView(Context context) {
        super(context);
        init();
    }

    public CropView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CropView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        arcHeight = getResources().getDimensionPixelOffset(R.dimen.row_size);
        setLayerType();
    }

    private void setLayerType() {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
            // looks like this is happening in some devices with lollipop and kitkat
            // trying to fix https://github.com/lifesum/bugs/issues/7040
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        } else {
            setLayerType(LAYER_TYPE_HARDWARE, null);
        }
    }

    private Path createClipPath(int height, int width) {
        final Path path = new Path();

        path.moveTo(0, 0);
        path.lineTo(0, height);
        path.quadTo(width / 2, height + arcHeight, width, height - arcHeight);

        path.lineTo(width, 0);
        path.close();

        return path;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) {
            int height = getMeasuredHeight();
            int width = getMeasuredWidth();
            clipPath = createClipPath(height, width);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (clipPath != null) {
            canvas.drawPath(clipPath, paint);
        }
    }
}

Below are the screenshots when Apidemos from android sample is run

Android P Android P Android 27 Android 27

Gaurav Vashisth
  • 7,547
  • 8
  • 35
  • 56
  • There's been issues relating to XferMode and HW acceleration; https://issuetracker.google.com/issues/36936096 . When this is supposed been fixed is slightly unclear though.. – harism Jul 26 '18 at 12:20

2 Answers2

2

As per the answer given by google this is intended behaviour.
https://issuetracker.google.com/issues/111819103

They gave 3 options

  1. Use android.view.ViewOutlineProvider (as per example here https://github.com/googlesamples/android-ClippingBasic).
  2. Replace the ImageView with a BitmapShader, which is fast (each pixel is drawn once) and more portable way as BitmapShader is supported in API level 1. Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.FILL); Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.spiderman); Shader shader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); paint.setShader(shader); Path corners = new Path(); corners.addRoundRect(bounds, radii, Path.Direction.CW); canvas.drawPath(corners, paint);
  3. Draw an inverse path with SRC_OVER on top of the ImageView. This works if background is solid color and it is slower, because some pixels are drawn twice.

Of these the first can't be used to render convex complex path as is answered in https://issuetracker.google.com/issues/37064491

Trying the other two options and post the results here.

Gaurav Vashisth
  • 7,547
  • 8
  • 35
  • 56
1

Yep, I have encountered the same problem.

Maybe Android-Pie does not seem to support drawerDuff.Mode on drawPath ...

But, you still can be use drawBitmap to cut layers.

E.g:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (clipPathBitmap != null) {
        canvas.drawBitmap(clipPathBitmap, 0, 0, paint);
    }
}

private void makeClipPathBitmap() {
    clipPathBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(mShapeBitmap);
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    p.setColor(Color.BLACK);
    clipPath.draw(c, p);
}
Gavin Liu
  • 786
  • 6
  • 7