Android alpha compositing (#50)

This change adds an ability for screen container on Android to apply the correct mechanism for transparent layer blending. This is specifically important as screens are usually a complex views that may displays many layers and while transitioning often opacity is used to animate these. When we detect screen transitioning we (a) turn on offscreen alpha compositing (which makes the opacity being applied for the whole screen layer at once instead of making all the children semi-transparent) and also (b) turn on hardware layer that makes offscreen compositing render to GPU (which is both faster and consumes only GPU memory).

In addition to that change we also need to disable wrapping Screen's children with View, as in such a case opacity is applied on the underlying View instead of a Screen. That workaround has been added because of a bug in Animated library and fixed in RN 0.57+
This commit is contained in:
Krzysztof Magiera
2018-12-20 09:06:28 +01:00
committed by GitHub
parent 4dd751811a
commit 68a02d58d7
3 changed files with 46 additions and 7 deletions

View File

@@ -2,6 +2,7 @@ package com.swmansion.rnscreens;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
@@ -36,6 +37,7 @@ public class Screen extends ViewGroup {
private final Fragment mFragment;
private @Nullable ScreenContainer mContainer;
private boolean mActive;
private boolean mTransitioning;
public Screen(Context context) {
super(context);
@@ -47,6 +49,33 @@ public class Screen extends ViewGroup {
// no-op
}
/**
* While transitioning this property allows to optimize rendering behavior on Android and provide
* a correct blending options for the animated screen. It is turned on automatically by the container
* when transitioning is detected and turned off immediately after
*/
public void setTransitioning(boolean transitioning) {
if (mTransitioning == transitioning) {
return;
}
mTransitioning = transitioning;
super.setLayerType(transitioning ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
}
@Override
public boolean hasOverlappingRendering() {
return mTransitioning;
}
@Override
public void setLayerType(int layerType, @Nullable Paint paint) {
// ignore layer type is controlled by `transitioning` prop
}
public void setNeedsOffscreenAlphaCompositing(boolean needsOffscreenAlphaCompositing) {
// ignore - offscreen alpha is controlled by `transitioning` prop
}
protected void setContainer(@Nullable ScreenContainer mContainer) {
this.mContainer = mContainer;
}

View File

@@ -158,6 +158,15 @@ public class ScreenContainer extends ViewGroup {
}
}
// detect if we are "transitioning" based on the number of active screens
int activeScreens = 0;
for (int i = 0, size = mScreens.size(); i < size; i++) {
if (isScreenActive(mScreens.get(i), mScreens)) {
activeScreens += 1;
}
}
boolean transitioning = activeScreens > 1;
// attach newly activated screens
boolean addedBefore = false;
for (int i = 0, size = mScreens.size(); i < size; i++) {
@@ -169,6 +178,7 @@ public class ScreenContainer extends ViewGroup {
} else if (isActive && addedBefore) {
moveToFront(screen);
}
screen.setTransitioning(transitioning);
}
tryCommitTransaction();
}