Skip to content

Android broken background with react-native 0.75.1  #226

Description

@MartinInAction

image

Left is android sim and right is iOS. I cant get rid of the black background on android since upgrading to RN 0.75.1. Prior versions worked great!!

Any ideas on how to fix this?

Activity

  1. maksim-v commented on Aug 19, 2024

    @maksim-v

    Same here
    I tried changing the background color in different ways, but nothing helped

  2. maksim-v commented on Aug 20, 2024

    @maksim-v

    @MartinInAction I found a temporary solution in case you are using hardware rendering mode. I haven't tested it with software mode. You just need to apply this patch:

    diff --git a/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java b/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    index 2ea0c5e..e8877e0 100644
    --- a/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    +++ b/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    @@ -41,6 +41,7 @@ public class RNCMaskedView extends ReactViewGroup {
     
         // draw the mask
         if (mBitmapMask != null) {
    +      setLayerType(LAYER_TYPE_HARDWARE, mPaint);
           mPaint.setXfermode(mPorterDuffXferMode);
           canvas.drawBitmap(mBitmapMask, 0, 0, mPaint);
           mPaint.setXfermode(null);
    
    

    Here I simply set the layer type in the dispatchDraw method, providing a Paint instance that controls how the layer is drawn on the screen. Here is the complete method:

      @Override
      protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
    
        if (mBitmapMaskInvalidated) {
          // redraw mask element to support animated elements
          updateBitmapMask();
    
          mBitmapMaskInvalidated = false;
        }
    
        // draw the mask
        if (mBitmapMask != null) {
          setLayerType(LAYER_TYPE_HARDWARE, mPaint);
          mPaint.setXfermode(mPorterDuffXferMode);
          canvas.drawBitmap(mBitmapMask, 0, 0, mPaint);
          mPaint.setXfermode(null);
        }
      }
    

    Hope this helps!

  3. MartinInAction commented on Aug 21, 2024

    @MartinInAction
    Author

    @maksim-v Thank you! you saved the day!!

  4. jasimchz commented on Aug 21, 2024

    @jasimchz

    I tried this but still, react-native-shimmer and react-native-skelton view has same issue

  5. MartinInAction commented on Aug 21, 2024

    @MartinInAction
    Author

    @jasimchz are you sure the patch is applied?

  6. dembeEdward commented on Aug 21, 2024

    @dembeEdward

    @MartinInAction I found a temporary solution in case you are using hardware rendering mode. I haven't tested it with software mode. You just need to apply this patch:

    diff --git a/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java b/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    index 2ea0c5e..e8877e0 100644
    --- a/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    +++ b/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    @@ -41,6 +41,7 @@ public class RNCMaskedView extends ReactViewGroup {
     
         // draw the mask
         if (mBitmapMask != null) {
    +      setLayerType(LAYER_TYPE_HARDWARE, mPaint);
           mPaint.setXfermode(mPorterDuffXferMode);
           canvas.drawBitmap(mBitmapMask, 0, 0, mPaint);
           mPaint.setXfermode(null);
    

    Here I simply set the layer type in the dispatchDraw method, providing a Paint instance that controls how the layer is drawn on the screen. Here is the complete method:

      @Override
      protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
    
        if (mBitmapMaskInvalidated) {
          // redraw mask element to support animated elements
          updateBitmapMask();
    
          mBitmapMaskInvalidated = false;
        }
    
        // draw the mask
        if (mBitmapMask != null) {
          setLayerType(LAYER_TYPE_HARDWARE, mPaint);
          mPaint.setXfermode(mPorterDuffXferMode);
          canvas.drawBitmap(mBitmapMask, 0, 0, mPaint);
          mPaint.setXfermode(null);
        }
      }
    

    Hope this helps!

    Worked like a charm

  7. jasimchz commented on Aug 22, 2024

    @jasimchz

    Anyone check if react-native-shimmer still broking?!

  8. efstathiosntonas commented on Aug 26, 2024

    @efstathiosntonas

    @maksim-v thanks, this was driving me crazy.

  9. lovegaoshi commented on Aug 26, 2024

    @lovegaoshi

    can confirm this works with software mode rendering mode as well. tysm!

    fyi the filename for the patch using patch-package is patches/@react-native-masked-view+masked-view+0.3.1.patch

  10. added a commit that references this issue on Sep 11, 2024
    3454d15
  11. kelvinkioko commented on Oct 1, 2024

    @kelvinkioko

    Anyone available to approve the PRs fixing this bug?

  12. AkilUnik commented on Oct 8, 2024

    @AkilUnik

    `package org.reactnative.maskedview;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffXfermode;
    import android.view.View;

    import com.facebook.react.views.view.ReactViewGroup;

    public class RNCMaskedView extends ReactViewGroup {
    private static final String TAG = "RNCMaskedView";

    private Bitmap mBitmapMask = null;
    private boolean mBitmapMaskInvalidated = false;
    private Paint mPaint;
    private PorterDuffXfermode mPorterDuffXferMode;

    public RNCMaskedView(Context context) {
    super(context);

    // Default to hardware rendering, androidRenderingMode prop will override
    setRenderingMode("hardware");
    
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPorterDuffXferMode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
    

    }

    @OverRide
    protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);

    if (mBitmapMaskInvalidated) {
      // redraw mask element to support animated elements
      updateBitmapMask();
    
      mBitmapMaskInvalidated = false;
    }
    
    // draw the mask
    if (mBitmapMask != null) {
      setLayerType(LAYER_TYPE_HARDWARE, mPaint);
      mPaint.setXfermode(mPorterDuffXferMode);
      canvas.drawBitmap(mBitmapMask, 0, 0, mPaint);
      mPaint.setXfermode(null);
    }
    

    }

    @OverRide
    public void onDescendantInvalidated(View child, View target) {
    super.onDescendantInvalidated(child, target);

    if (!mBitmapMaskInvalidated) {
      View maskView = getChildAt(0);
      if (maskView != null) {
        if (maskView.equals(child)) {
          mBitmapMaskInvalidated = true;
        }
      }
    }
    
    invalidate();
    

    }

    @OverRide
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);

    if (changed) {
      mBitmapMaskInvalidated = true;
    }
    

    }

    @OverRide
    protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    mBitmapMaskInvalidated = true;
    }

    private void updateBitmapMask() {
    View maskView = getChildAt(0);
    if (maskView != null) {
    maskView.setVisibility(View.VISIBLE);
    if (this.mBitmapMask != null) {
    this.mBitmapMask.recycle();
    }
    this.mBitmapMask = getBitmapFromView(maskView);
    maskView.setVisibility(View.INVISIBLE);
    }
    }

    public static Bitmap getBitmapFromView(final View view) {
    view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());

    if (view.getMeasuredWidth() <= 0 || view.getMeasuredHeight() <= 0) {
      return null;
    }
    
    final Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(),
            view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
    
    final Canvas canvas = new Canvas(bitmap);
    
    view.draw(canvas);
    
    return bitmap;
    

    }

    public void setRenderingMode(String renderingMode) {
    if (renderingMode.equals("software")) {
    setLayerType(LAYER_TYPE_SOFTWARE, null);
    } else {
    setLayerType(LAYER_TYPE_HARDWARE, null);
    }
    }
    }
    `

    if any one want full file code there it is just copy and change RNCMaskedView.java file

  13. rafaelmaeuer commented on Oct 26, 2024

    @rafaelmaeuer

    @MartinInAction I found a temporary solution in case you are using hardware rendering mode. I haven't tested it with software mode. You just need to apply this patch:

    diff --git a/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java b/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    index 2ea0c5e..e8877e0 100644
    --- a/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    +++ b/node_modules/@react-native-masked-view/masked-view/android/src/main/java/org/reactnative/maskedview/RNCMaskedView.java
    @@ -41,6 +41,7 @@ public class RNCMaskedView extends ReactViewGroup {
     
         // draw the mask
         if (mBitmapMask != null) {
    +      setLayerType(LAYER_TYPE_HARDWARE, mPaint);
           mPaint.setXfermode(mPorterDuffXferMode);
           canvas.drawBitmap(mBitmapMask, 0, 0, mPaint);
           mPaint.setXfermode(null);
    

    Here I simply set the layer type in the dispatchDraw method, providing a Paint instance that controls how the layer is drawn on the screen. Here is the complete method:

      @Override
      protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
    
        if (mBitmapMaskInvalidated) {
          // redraw mask element to support animated elements
          updateBitmapMask();
    
          mBitmapMaskInvalidated = false;
        }
    
        // draw the mask
        if (mBitmapMask != null) {
          setLayerType(LAYER_TYPE_HARDWARE, mPaint);
          mPaint.setXfermode(mPorterDuffXferMode);
          canvas.drawBitmap(mBitmapMask, 0, 0, mPaint);
          mPaint.setXfermode(null);
        }
      }
    

    Hope this helps!

    This patch does solve the Problem on Android, however on slow/old devices it freezes the app for some seconds and causes some really bad hangs/delays (using masked view in an animation). Has anyone experiences something similar with this fix?

  14. samueljim commented on Nov 3, 2024

    @samueljim

    #228 this merge will fix this issue. I've tested it

  15. added a commit that references this issue on Nov 4, 2024
    34ddff1
  16. musasoftlabx commented on Dec 11, 2024

    @musasoftlabx

    this works 👍. hope its fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions