I am trying to integrate Android Fragment with react native's new architecture fabric. I am following the guide from over here unfortunately they have not specified any docs for integrating fragment so I was taking help from the old architecture over here
I have created following kotlin files, the rest of the code of adding typescript interface remains the same
class CenteredText(context: Context): LinearLayout(context){
private var textView: TextView
private var secondtextView: TextView
init {
val layoutParams: ViewGroup.LayoutParams =
LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
setLayoutParams(layoutParams)
orientation = VERTICAL
textView = TextView(context)
addView(textView)
secondtextView = TextView(context)
addView(secondtextView)
secondtextView.text = "Hello I am second"
secondtextView.textSize = 25F
secondtextView.setTextColor(Color.RED)
}
fun configureText(text: String){
textView.text = text
}
}
class CenteredTextManager(private val context: ReactApplicationContext) :
ViewGroupManager<FrameLayout>() {
private val create = "create"
private var propWidth: Int? = null
private var propHeight: Int? = null
override fun getName(): String {
return NAME
}
override fun createViewInstance(reactContext: ThemedReactContext) = FrameLayout(reactContext)
companion object {
const val NAME = "RTNCenteredText"
private const val COMMAND_CREATE = 1
}
override fun getCommandsMap() = mapOf(create to COMMAND_CREATE)
override fun receiveCommand(root: FrameLayout, commandId: String?, args: ReadableArray?) {
super.receiveCommand(root, commandId, args)
val reactNativeViewId = requireNotNull(args).getInt(0)
Log.i("argumentsare", args.toString())
when (commandId?.toInt()) {
COMMAND_CREATE -> createFragment(root, reactNativeViewId)
}
}
private fun setupLayout(view: View) {
Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
manuallyLayoutChildren(view)
view.viewTreeObserver.dispatchOnGlobalLayout()
Choreographer.getInstance().postFrameCallback(this)
}
})
}
private fun manuallyLayoutChildren(view: View) {
// propWidth and propHeight coming from react-native props
val width = requireNotNull(propWidth)
val height = requireNotNull(propHeight)
view.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
)
view.layout(0, 0, width, height)
}
private fun createFragment(root: FrameLayout, reactNativeViewId: Int) {
val parentView = root.findViewById<ViewGroup>(reactNativeViewId)
setupLayout(parentView)
val myFragment = CenteredTextFragment()
val activity = context.currentActivity as FragmentActivity
activity.supportFragmentManager
.beginTransaction()
.replace(reactNativeViewId, myFragment, reactNativeViewId.toString())
.commit()
}
}
class CenteredTextFragment: Fragment() {
private lateinit var centeredText: CenteredText
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
centeredText = CenteredText(requireNotNull(context))
return centeredText // this CustomView could be any view that you want to render
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onDestroy() {
super.onDestroy()
}
}
class CenteredTextPackage : ReactPackage {
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return Collections.singletonList(CenteredTextManager(reactContext))
}
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return emptyList()
}
}
Full source code over here
Try setting
before doing
Another potential solution is to override the
onResume
andonPause
functions in your fragment and force them to callgetReactInstanceManager().onHostResume(getActivity(), this);
andgetReactInstanceManager().onHostPause(getActivity());
respectively.Alternatively, If you don't want to use Fabric, change the application onCreate method
ReactNativeHost.getUseFabric()
to returnfalse
.