Fix text input scroll when status bar is translucent

Summary:Changed the implementation of `setTranslucent` because the old one used the view flag SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN which has the sad side effect of making the ScrollViews not adjust properly when the keyboard is opened. Instead I use `setOnApplyWindowInsetsListener` to hook in the insets calculation process and consume the top offset so the decor view doesn't add top padding for the status bar.

I also limited the translucent prop to API 21+ because `setOnApplyWindowInsetsListener` is not available before that and anyway the translucent prop is only useful with a semi-transparent status bar color which only works on API 21+.

**Test plan**
Reproduced the bug using this code in UIExplorer.
https://gist.github.com/janicduplessis/217b9994e35f960a1793

Tapping a text field that would be hidden by the soft keyboard should scroll the view so it is not hidden.

Also tested that setting the translucent prop on and off still works as before.

Fixes #6455
Closes https://github.com/facebook/react-native/pull/6481

Differential Revision: D3067199

Pulled By: mkonicek

fb-gh-sync-id: aa115f8688ac7e461e62c18ebb8ab77350d000f8
shipit-source-id: aa115f8688ac7e461e62c18ebb8ab77350d000f8
This commit is contained in:
Janic Duplessis 2016-03-17 16:59:33 -07:00 committed by Facebook Github Bot 0
parent 18f38ecdc0
commit c76523f1ad
1 changed files with 32 additions and 14 deletions

View File

@ -17,6 +17,7 @@ import android.content.Context;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import java.util.Map;
@ -112,22 +113,39 @@ public class StatusBarModule extends ReactContextBaseJavaModule {
res.reject(ERROR_NO_ACTIVITY, ERROR_NO_ACTIVITY_MESSAGE);
return;
}
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
int flags = activity.getWindow().getDecorView().getSystemUiVisibility();
if (translucent) {
flags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
} else {
flags &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void run() {
// If the status bar is translucent hook into the window insets calculations
// and consume all the top insets so no padding will be added under the status bar.
View decorView = activity.getWindow().getDecorView();
if (translucent) {
decorView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
@Override
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
WindowInsets defaultInsets = v.onApplyWindowInsets(insets);
return defaultInsets.replaceSystemWindowInsets(
defaultInsets.getSystemWindowInsetLeft(),
0,
defaultInsets.getSystemWindowInsetRight(),
defaultInsets.getSystemWindowInsetBottom()
);
}
});
} else {
decorView.setOnApplyWindowInsetsListener(null);
}
ViewCompat.requestApplyInsets(decorView);
res.resolve(null);
}
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
ViewCompat.requestApplyInsets(activity.getWindow().getDecorView());
res.resolve(null);
}
}
);
);
}
}
@ReactMethod