I am trying to create a native ui with fragment on android
CealScanQrView.kt
class CealScanQrView(context: Context): FrameLayout(context) {
...
//Contains all the logic of integrating camerax, check below code repo to see the full source code
...
//Now while submitting the data from native side to react-native I get error
val reactContext = context as ReactContext ///This line causes error and makes my app crash
reactContext
.getJSModule(RCTEventEmitter::class.java)
.receiveEvent(id, topChange, event)
}
CealScanQrFragment.kt
class CealScanQrFragment: Fragment() {
private lateinit var cealScanQrView: CealScanQrView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
cealScanQrView = CealScanQrView(requireNotNull(context))
return cealScanQrView // this CustomView could be any view that you want to render
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// do any logic that should happen in an `onCreate` method, e.g:
cealScanQrView.setUpCamera(requireActivity())
}
override fun onDestroy() {
super.onDestroy()
cealScanQrView.destroyCamera()
}
}
CealScanQrViewManager.kt
class CealScanQrViewManager(
private val reactContext: ReactApplicationContext
) : ViewGroupManager<FrameLayout>() {
private val cealScanQrView = "CealScanQrView"
private val topChange = "topChange"
private val phasedRegistrationNames = "phasedRegistrationNames"
private val bubbled = "bubbled"
private val onChange = "onChange"
private val create = "create"
companion object {
private const val COMMAND_CREATE = 1
}
private var propWidth: Int? = null
private var propHeight: Int? = null
override fun getName() = cealScanQrView
override fun createViewInstance(reactContext: ThemedReactContext) = FrameLayout(reactContext)
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)
when (commandId?.toInt()) {
COMMAND_CREATE -> createFragment(root, reactNativeViewId)
}
}
private fun createFragment(root: FrameLayout, reactNativeViewId: Int) {
val parentView = root.findViewById<ViewGroup>(reactNativeViewId)
setupLayout(parentView)
val myFragment = CealScanQrFragment()
val activity = reactContext.currentActivity as FragmentActivity
activity.supportFragmentManager
.beginTransaction()
.replace(reactNativeViewId, myFragment, reactNativeViewId.toString())
.commit()
}
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)
}
})
}
@ReactPropGroup(names = ["width", "height"], customType = "Style")
fun setStyle(view: FrameLayout, index: Int, value: Int) {
if (index == 0) propWidth = value
if (index == 1) propHeight = value
}
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)
}
override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
return mapOf(
topChange to mapOf(
phasedRegistrationNames to mapOf(
bubbled to onChange
)
)
)
}
}
val reactContext = context as ReactContext causes the app to crash and throw error saying
java.lang.ClassCastException: com.myapp.MainActivity cannot be cast to com.facebook.react.bridge.ReactContext
What kind of context I should pass from my fragment to Native UI View so I can use getJSModule method to send data
Full source code here