I have added a dynamic generated FrameLayout to a react-native view. The Framelayout is showing up. but when I add a fragment to the view, nothing is showing.
here is a part of the code:
public FrameLayout createViewInstance(ThemedReactContext context) {
Fragment fragment = MapFragment.newInstance(mapKey);
FrameLayout view = new FrameLayout(context);
view.setWillNotDraw(false);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
view.setLayoutParams(lp);
view.setId(View.generateViewId());
view.setBackgroundColor(Color.parseColor("#1FFDDB"));
FragmentActivity activity = MainActivity.getFragmentActivity();
FragmentManager fragmentManager = activity.getSupportFragmentManager();
fragmentManager.beginTransaction().remove(fragment).commit();
fragmentManager.executePendingTransactions();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(0, fragment);
fragmentTransaction.show(fragment);
fragmentTransaction.attach(fragment);
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
return view;
}
When I add a TextView to the view it is showing:
// add a textfield to the view
TextView textView1 = new TextView(context);
textView1.setText("Android");
textView1.setTextSize(30);
textView1.setGravity(Gravity.CENTER);
view.setVisibility(View.VISIBLE);
view.addView(textView1);
so there is an issue with the Fragment. any ideas why the fragment is not showing up?
I also encountered this problem and found the solution.
Android side:
First, create a layout_container.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Then inflate it in createViewInstance
method and define function to add fragment to the container.
@Override
public String getName() {
return "ExampleFragment";
}
@Override
protected View createViewInstance(ThemedReactContext reactContext) {
mContext = context;
LinearLayout root = (LinearLayout) LayoutInflater.from(reactContext)
.inflate(R.layout.layout_container, null);
return root;
}
@Nullable
@Override
public Map<String, Integer> getCommandsMap() {
return MapBuilder.of(
"create", COMMAND_CREATE
);
}
@Override
public void receiveCommand(View view, int commandId, @Nullable ReadableArray args) {
Log.d(TAG, "receiveCommand: " + commandId);
switch (commandId) {
case COMMAND_CREATE:
createFragment();
break;
}
}
private void createFragment() {
MapFragment mapFragment = new MapFragment();
mContext.getCurrentActivity()
.getFragmentManager()
.beginTransaction()
.add(R.id.container, mapFragment)
.commit();
}
RN side:
create Native UI Component Fragment.js
import {NativeModules, requireNativeComponent, View, UIManager, findNodeHandle} from 'react-native';
const fragmentIFace = {
name: "Fragment",
propTypes: {
...View.propTypes,
}
};
const NativeFragment = requireNativeComponent("ExampleFragment", fragmentIFace);
class ExampleFragment extends Component {
fragment;
render() {
return <NativeFragment
ref={c => this.fragment = c}
{...this.props} style={{flex: 1}}/>
}
create = () => {
UIManager.dispatchViewManagerCommand(
findNodeHandle(this.fragment),
UIManager.MapFragment.Commands.create,
[] // No args
)
}
export default ExampleFragment
then you can use it in RN.
class App extends Component {
componentDidMount() {
this.fragment.create();
}
render() {
return (
<View>
<ExampleFragment ref={r=>this.fragment = r} />
</View>
);
}
}
Here's the explanation:
In your code, you try to add fragment to the view which cannot be a fragment container.
Usually, View.generateViewId()
will return id 0x1
which is duplicated with ReactRootView
by coincidence so that your app will not crash. If you set other id to the container view, you will get exception and app will crash because the id of your view can not be found from current app's layout.
You can check it with Layout Inspector in Android Studio.
To prevent from duplication of ids, the best way is defining them in xml.
And that's why I inflate a root view from xml.
But if you set id for the root(LinearLayout
in my example), the id will be removed by RN when it is added, so the child is necessary.
After RN get the root view(didComponentMount()
), then you need to call create() from RN component, and you can see it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With