Fix header rendering – layout and transparency (#184)

* Let UINavController control subcontroller view's frames.

This PR changes the way we've been handling yoga <> NavController layout interactions. Now we ignore frame updates coming from react for the main Screen view to allow NavController take the controll. In order to keep yoga working we now use `setSize` to pass the dimensions of the view back to yoga such that it can properly calculate layout of the views under Screen component.

* Header resizing fixes for Android.

In this change we use CoordinatorLayout as a stack screen container to handle rendering of toolbar and screen content. Thanks to this approach we can support collapsable bars in the future. Instead of relying on RN to layout screen container when renered under ScreenStack we rely on Android native layout to measure and position screen content and then use UIManager.setNodeSize to communicate that back to react.
This commit is contained in:
Krzysztof Magiera
2019-10-18 15:08:39 +02:00
committed by GitHub
parent c590283359
commit 4a9a3a877a
10 changed files with 309 additions and 217 deletions

View File

@@ -1,6 +1,7 @@
package com.swmansion.rnscreens;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
@@ -16,42 +17,10 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.views.text.ReactFontManager;
public class ScreenStackHeaderConfig extends ViewGroup {
private static final float TOOLBAR_ELEVATION = PixelUtil.toPixelFromDIP(4);
private static final class ToolbarWithLayoutLoop extends Toolbar {
private final Runnable mLayoutRunnable = new Runnable() {
@Override
public void run() {
mLayoutEnqueued = false;
measure(
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
}
};
private boolean mLayoutEnqueued = false;
public ToolbarWithLayoutLoop(Context context) {
super(context);
}
@Override
public void requestLayout() {
super.requestLayout();
if (!mLayoutEnqueued) {
mLayoutEnqueued = true;
post(mLayoutRunnable);
}
}
}
private final ScreenStackHeaderSubview mConfigSubviews[] = new ScreenStackHeaderSubview[3];
private int mSubviewsCount = 0;
private String mTitle;
@@ -63,20 +32,18 @@ public class ScreenStackHeaderConfig extends ViewGroup {
private boolean mIsBackButtonHidden;
private boolean mIsShadowHidden;
private int mTintColor;
private int mWidth;
private int mHeight;
private final Toolbar mToolbar;
private OnBackPressedCallback mBackCallback = new OnBackPressedCallback(false) {
@Override
public void handleOnBackPressed() {
getScreenStack().dismiss(getScreen());
getScreenStack().dismiss(getScreenFragment());
}
};
private OnClickListener mBackClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
getScreenStack().dismiss(getScreen());
getScreenStack().dismiss(getScreenFragment());
}
};
@@ -84,36 +51,18 @@ public class ScreenStackHeaderConfig extends ViewGroup {
super(context);
setVisibility(View.GONE);
mToolbar = new ToolbarWithLayoutLoop(context);
mToolbar = new Toolbar(context);
// set primary color as background by default
TypedValue tv = new TypedValue();
if (context.getTheme().resolveAttribute(android.R.attr.colorPrimary, tv, true)) {
mToolbar.setBackgroundColor(tv.data);
}
mWidth = 0;
mHeight = 0;
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
mHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}
}
private void updateToolbarLayout() {
mToolbar.measure(
View.MeasureSpec.makeMeasureSpec(mWidth, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(mHeight, View.MeasureSpec.EXACTLY));
mToolbar.layout(0, 0, mWidth, mHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mWidth != (r - l)) {
mWidth = (r - l);
updateToolbarLayout();
}
// no-op
}
@Override
@@ -141,10 +90,13 @@ public class ScreenStackHeaderConfig extends ViewGroup {
return null;
}
private Fragment getScreenFragment() {
private ScreenStackFragment getScreenFragment() {
ViewParent screen = getParent();
if (screen instanceof Screen) {
return ((Screen) screen).getFragment();
Fragment fragment = ((Screen) screen).getFragment();
if (fragment instanceof ScreenStackFragment) {
return (ScreenStackFragment) fragment;
}
}
return null;
}
@@ -159,16 +111,16 @@ public class ScreenStackHeaderConfig extends ViewGroup {
Screen parent = (Screen) getParent();
if (mIsHidden) {
if (mToolbar.getParent() != null) {
parent.removeView(mToolbar);
getScreenFragment().removeToolbar();
}
return;
}
if (mToolbar.getParent() == null) {
parent.addView(mToolbar);
getScreenFragment().setToolbar(mToolbar);
}
AppCompatActivity activity = (AppCompatActivity) parent.getFragment().getActivity();
AppCompatActivity activity = (AppCompatActivity) getScreenFragment().getActivity();
activity.setSupportActionBar(mToolbar);
ActionBar actionBar = activity.getSupportActionBar();
@@ -188,7 +140,7 @@ public class ScreenStackHeaderConfig extends ViewGroup {
// shadow
actionBar.setElevation(mIsShadowHidden ? 0 : TOOLBAR_ELEVATION);
getScreenFragment().setToolbarShadowHidden(mIsShadowHidden);
// title
actionBar.setTitle(mTitle);