Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does React Native Really Support Android Fragments?

This question is harder to answer than it appears.

  • ReactFragmentActivity does exist in master branch of React Native, BUT

  • There is an open issue to create a React Fragment see https://github.com/facebook/react-native/pull/12199/commits/e5b68717f57c41f5f1e77c289bdb4f673bb242f1 // This has not been approved yet, but the need was acknowledged.

  • I have looked at dozens of React Native examples on github etc, and fragments are never shown. Prove me wrong please!

  • It's apparently not impossible see: React-native inside a Fragment but this solution seems not to fully deal with touch events.

My impression is that React Native is primarily focused around controlling the root view of the whole activity for layouts. I think there is some caution being used in taking on fragments. As a side note React itself (not React Native) seems to have its own concept of a fragment. I am guessing even Yoga layout manager inside React Native flexible as it is does not want to deal with Android Fragments. Not an issue so much for new apps but for integrating React Native into existing apps this is real issue!

like image 721
gitsensible Avatar asked May 05 '17 04:05

gitsensible


People also ask

Can I use fragment in React Native?

You can render your React Native component into a Fragment instead of a full screen React Native Activity. The component may be termed a "screen" or "fragment" and it will function in the same manner as an Android fragment, likely containing child components.

Does React Native support Android?

React Native combines the best parts of native development with React, a best-in-class JavaScript library for building user interfaces. Use a little—or a lot. You can use React Native today in your existing Android and iOS projects or you can create a whole new app from scratch.

Are fragments still used in Android?

Using the support library, fragments are supported back to all relevant Android versions. Fragments encapsulate views and logic so that it is easier to reuse within activities.


1 Answers

I don't know, perhaps you already found the solution, but it can be helpful for someone else. The solution, you provided is really has some issues with touch events when you use native android FragmentActivity or AppCompatActivity. But the react-native has own ReactFragmentActivity and if your activity extends this activity, the touch events works well, but only in separated fragment. It does not work with ViewPager and others. Only if fragment uses in separated Activity, like this:

Fragment reactFragment = new MainReactFragment(); getSupportFragmentManager().beginTransaction().replace(R.id.fragment, reactFragment, "reactFragment").commit(); 

EDIT:

After some trials and errors,I got it to correct work with ViewPager and TabLayout(but I think in other cases it will work as well).So, here is what I did. The ReactFragment looks like this:

public abstract class ReactFragment extends Fragment {      private ReactRootView mReactRootView;     private ReactInstanceManager mReactInstanceManager;      // This method returns the name of our top-level component to show     public abstract String getMainComponentName();      @Override     public void onAttach(Context context) {         super.onAttach(context);         mReactRootView = new ReactRootView(context);     }      public void setmReactInstanceManager(ReactInstanceManager mReactInstanceManager){         this.mReactInstanceManager = mReactInstanceManager;     }      @Override     public ReactRootView onCreateView(LayoutInflater inflater, ViewGroup group, Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         return mReactRootView;     }      @Override     public void onActivityCreated(Bundle savedInstanceState) {         super.onActivityCreated(savedInstanceState);         mReactRootView.startReactApplication(                 mReactInstanceManager,                 getMainComponentName(),                 null         );     } } 

Then implement our fragment:

public class MainReactFragment extends ReactFragment {      @Override     public String getMainComponentName() {         return "reactProject";     } } 

We need to extend our activity from ReactFragmentActivity and initialize ReactInstanceManager:

public class MainActivity extends ReactFragmentActivity {      TabLayout tabs;     ViewPager viewPager;     private ReactInstanceManager mReactInstanceManager;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.layout_main);          tabs = (TabLayout) findViewById(R.id.menuItemTabs);         viewPager = (ViewPager) findViewById(R.id.tabMainMenu);          mReactInstanceManager = ReactInstanceManager.builder()                 .setApplication(getApplication())                 .setBundleAssetName("index.android.bundle")                 .setJSMainModuleName("index.android")                 .addPackage(new MainReactPackage())                 .setUseDeveloperSupport(BuildConfig.DEBUG)                 .setInitialLifecycleState(LifecycleState.RESUMED)                 .build();          TabsAdapter adapter = new TabsAdapter(getSupportFragmentManager(), mReactInstanceManager);         viewPager.setAdapter(adapter);         tabs.setupWithViewPager(viewPager);              }      @Override     public boolean onKeyUp(int keyCode, KeyEvent event) {         if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {             mReactInstanceManager.showDevOptionsDialog();             return true;         }         return super.onKeyUp(keyCode, event);     }      @Override     public void invokeDefaultOnBackPressed() {         super.onBackPressed();     }      @Override     public void onPause() {         super.onPause();          if (mReactInstanceManager != null) {             mReactInstanceManager.onHostPause(this);         }     }      @Override     public void onResume() {         super.onResume();          if (mReactInstanceManager != null) {             mReactInstanceManager.onHostResume(this, this);         }     }      @Override     public void onBackPressed() {         if (mReactInstanceManager != null) {             mReactInstanceManager.onBackPressed();         }         else {             super.onBackPressed();         }     } } 

And, of course, TabAdapter:

public class TabsAdapter extends FragmentStatePagerAdapter {      ReactInstanceManager mReactInstanceManager;      public TabsAdapter(FragmentManager fragmentManager, `enter code here`ReactInstanceManager reactInstanceManager){         super(fragmentManager);         mReactInstanceManager = reactInstanceManager;     }      @Override     public Fragment getItem(int position) {         MainReactFragment reactFragment = new MainReactFragment();         reactFragment.setmReactInstanceManager(mReactInstanceManager);         return reactFragment;     }      @Override     public int getCount() {         return 2;     }      @Override     public int getItemPosition(Object item) {         return POSITION_NONE;     }      @Override     public CharSequence getPageTitle(int position) {         return "react tab " + position;     }       @Override     public Parcelable saveState() {         return null;     } } 

RESULT:

enter image description here,

enter image description here,

enter image description here,

enter image description here

like image 53
Dmitriy Miyai Avatar answered Sep 18 '22 16:09

Dmitriy Miyai