1"use strict";(self.webpackChunkreact_native_website=self.webpackChunkreact_native_website||[]).push([["12132"],{41993(e,n,a){a.r(n),a.d(n,{metadata:()=>r,default:()=>g,frontMatter:()=>d,contentTitle:()=>u,toc:()=>m,assets:()=>p});var r=JSON.parse('{"id":"legacy/native-components-android","title":"Android Native UI Components","description":"There are tons of native UI widgets out there ready to be used in the latest apps - some of them are part of the platform, others are available as third-party libraries, and still more might be in use in your very own portfolio. React Native has several of the most critical platform components already wrapped, like ScrollView and TextInput, but not all of them, and certainly not ones you might have written yourself for a previous app. Fortunately, we can wrap up these existing components for seamless integration with your React Native application.","source":"@site/versioned_docs/version-0.82/legacy/native-components-android.md","sourceDirName":"legacy","slug":"/legacy/native-components-android","permalink":"/docs/0.82/legacy/native-components-android","draft":false,"unlisted":false,"editUrl":"[{\\"label\\":\\"Edit page for next release\\",\\"href\\":\\"https://github.com/facebook/react-native-website/edit/main/docs/legacy/native-components-android.md\\"},{\\"label\\":\\"Edit page for 0.82 release\\",\\"href\\":\\"https://github.com/facebook/react-native-website/edit/main/website/versioned_docs/version-0.82/legacy/native-components-android.md\\"}]","tags":[],"version":"0.82","lastUpdatedAt":1780494561000,"frontMatter":{"id":"native-components-android","title":"Android Native UI Components"},"sidebar":"docs","previous":{"title":"Local libraries setup","permalink":"/docs/0.82/legacy/local-library-setup"},"next":{"title":"iOS Native UI Components","permalink":"/docs/0.82/legacy/native-components-ios"}}'),t=a(62540),i=a(43023),o=a(77779),l=a(98263),s=a(38469),c=a(11551);let d={id:"native-components-android",title:"Android Native UI Components"},u,p={},m=[...c.RM,{value:"ImageView example",id:"imageview-example",level:2},{value:"1. Create the <code>ViewManager</code> subclass",id:"1-create-the-viewmanager-subclass",level:3},{value:"2. Implement method <code>createViewInstance</code>
1",id:"2-implement-method-createviewinstance",level:3},{value:"3. Expose view property setters using <code>@ReactProp</code> (or <code>@ReactPropGroup</code>) annotation",id:"3-expose-view-property-setters-using-reactprop-or-reactpropgroup-annotation",level:3},{value:"4. Register the <code>ViewManager</code>",id:"4-register-the-viewmanager",level:3},{value:"5. Implement the JavaScript module",id:"5-implement-the-javascript-module",level:3},{value:"Events",id:"events",level:2},{value:"Integration with an Android Fragment example",id:"integration-with-an-android-fragment-example",level:2},{value:"1. Create an example custom view",id:"1-create-an-example-custom-view",level:3},{value:"2. Create a <code>Fragment</code>",id:"2-create-a-fragment",level:3},{value:"3. Create the <code>ViewManager</code> subclass",id:"3-create-the-viewmanager-subclass",level:3},{value:"4. Register the <code>ViewManager</code>",id:"4-register-the-viewmanager-1",level:3},{value:"5. Register the <code>Package</code>",id:"5-register-the-package",level:3},{value:"6. Implement the JavaScript module",id:"6-implement-the-javascript-module",level:3}];function h(e){let n={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",...(0,i.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(c.Ay,{}),"\n",(0,t.jsxs)(n.p,{children:["There are tons of native UI widgets out there ready to be used in the latest apps - some of them are part of the platform, others are available as third-party libraries, and still more might be in use in your very own portfolio. React Native has several of the most critical platform components already wrapped, like ",(0,t.jsx)(n.code,{children:"ScrollView"})," and ",(0,t.jsx)(n.code,{children:"TextInput"}),", but not all of them, and certainly not ones you might have written yourself for a previous app. Fortunately, we can wrap up these existing components for seamless integration with your React Native application."]}),"\n",(0,t.jsxs)(n.p,{children:["Like the native module guide, this too is a more advanced guide that assumes you are somewhat familiar with Android SDK programming. This guide will show you how to build a native UI component, walking you through the implementation of a subset of the existing ",(0,t.jsx)(n.code,{children:"ImageView"})," component available in the core React Native library."]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["You can also setup local library containing native component with one command. Read the guide to ",(0,t.jsx)(n.a,{href:"local-library-setup",children:"Local libraries setup"})," for more details."]})}),"\n",(0,t.jsx)(n.h2,{id:"imageview-example",children:"ImageView example"}),"\n",(0,t.jsx)(n.p,{children:"For this example we are going to walk through the implementation requirements to allow the use of ImageViews in JavaScript."}),"\n",(0,t.jsxs)(n.p,{children:["Native views are created and manipulated by extending ",(0,t.jsx)(n.code,{children:"ViewManager"})," or more commonly ",(0,t.jsx)(n.code,{children:"SimpleViewManager"})," . A ",(0,t.jsx)(n.code,{children:"SimpleViewManager"})," is convenient in this case because it applies common properties such as background color, opacity, and Flexbox layout."]}),"\n",(0,t.jsxs)(n.p,{children:["These subclasses are essentially singletons - only one instance of each is created by the bridge. They send native views to the ",(0,t.jsx)(n.code,{children:"NativeViewHierarchyManager"}),", which delegates back to them to set and update the properties of the views as necessary. The ",(0,t.jsx)(n.code,{children:"ViewManagers"})," are also typically the delegates for the views, sending events back to JavaScript via the bridge."]}),"\n",(0,t.jsx)(n.p,{children:"To send a view:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsx)(n.li,{children:"Create the ViewManager subclass."}),"\n",(0,t.jsxs)(n.li,{children:["Implement the ",(0,t.jsx)(n.code,{children:"createViewInstance"})," method"]}),"\n",(0,t.jsxs)(n.li,{children:["Expose view property setters using ",(0,t.jsx)(n.code,{children:"@ReactProp"})," (or ",(0,t.jsx)(n.code,{children:"@ReactPropGroup"}),") annotation"]}),"\n",(0,t.jsxs)(n.li,{children:["Register the manager in ",(0,t.jsx)(n.code,{children:"createViewManagers"})," of the applications package."]}),"\n",(0,t.jsx)(n.li,{children:"Implement the JavaScript module"}),"\n"]}),"\n",(0,t.jsxs)(n.h3,{id:"1-create-the-viewmanager-subclass",children:["1. Create the ",(0,t.jsx)(n.code,{children:"ViewM
1anager"})," subclass"]}),"\n",(0,t.jsxs)(n.p,{children:["In this example we create view manager class ",(0,t.jsx)(n.code,{children:"ReactImageManager"})," that extends ",(0,t.jsx)(n.code,{children:"SimpleViewManager"})," of type ",(0,t.jsx)(n.code,{children:"ReactImageView"}),". ",(0,t.jsx)(n.code,{children:"ReactImageView"})," is the type of object managed by the manager, this will be the custom native view. Name returned by ",(0,t.jsx)(n.code,{children:"getName"})," is used to reference the native view type from JavaScript."]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="Kotlin"',children:'class ReactImageManager(\r\n private val callerContext: ReactApplicationContext\r\n) : SimpleViewManager<ReactImageView>() {\r\n\r\n override fun getName() = REACT_CLASS\r\n\r\n companion object {\r\n const val REACT_CLASS = "RCTImageView"\r\n }\r\n}\n'})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="Java"',children:'public class ReactImageManager extends SimpleViewManager<ReactImageView> {\r\n\r\n public static final String REACT_CLASS = "RCTImageView";\r\n ReactApplicationContext mCallerContext;\r\n\r\n public ReactImageManager(ReactApplicationContext reactContext) {\r\n mCallerContext = reactContext;\r\n }\r\n\r\n @Override\r\n public String getName() {\r\n return REACT_CLASS;\r\n }\r\n}\n'})})})]}),"\n",(0,t.jsxs)(n.h3,{id:"2-implement-method-createviewinstance",children:["2. Implement method ",(0,t.jsx)(n.code,{children:"createViewInstance"})]}),"\n",(0,t.jsxs)(n.p,{children:["Views are created in the ",(0,t.jsx)(n.code,{children:"createViewInstance"})," method, the view should initialize itself in its default state, any properties will be set via a follow up call to ",(0,t.jsx)(n.code,{children:"updateView."})]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="Kotlin"',children:" override fun createViewInstance(context: ThemedReactContext) =\r\n ReactImageView(context, Fresco.newDraweeControllerBuilder(), null, callerContext)\n"})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="Java"',children:" @Override\r\n public ReactImageView createViewInstance(ThemedReactContext context) {\r\n return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), null, mCallerContext);\r\n }\n"})})})]}),"\n",(0,t.jsxs)(n.h3,{id:"3-expose-view-property-setters-using-reactprop-or-reactpropgroup-annotation",children:["3. Expose view property setters using ",(0,t.jsx)(n.code,{children:"@ReactProp"})," (or ",(0,t.jsx)(n.code,{children:"@ReactPropGroup"}),") annotation"]}),"\n",(0,t.jsxs)(n.p,{children:["Properties that are to be reflected in JavaScript needs to be exposed as setter method annotated with ",(0,t.jsx)(n.code,{children:"@ReactProp"})," (or ",(0,t.jsx)(n.code,{children:"@ReactPropGroup"}),"). Setter method should take view to be updated (of the current view type) as a first argument and property value as a second argument. Setter should be public and not return a value (i.e. return type should be ",(0,t.jsx)(n.code,{children:"void"})," in Java or ",(0,t.jsx)(n.code,{children:"Unit"})," in Kotlin). Property type sent to JS is determined automatically based on the type of value argument of the setter. The following type of values are currently supported (in Java): ",(0,t.jsx)(n.code,{children:"boolean"}),", ",(0,t.jsx)(n.code,{children:"int"}),", ",(0,t.jsx)(n.code,{children:"float"}),", ",(0,t.jsx)(n.code,{children:"double"}),", ",(0,t.jsx)(n.code,{children:"String"}),", ",(0,t.jsx)(n.code,{children:"Boolean"}),", ",(0,t.jsx)(n.code,{children:"Integer"}),", ",(0,t.jsx)(n.code,{children:"ReadableArray"}),", ",(0,t.jsx)(n.code,{children:"ReadableMap"}),". The corresponding types in Kotlin are ",(0,t.jsx)(n.code,{children:"Boolean"}),", ",(0,t.jsx)(n.code,{children:"Int"}),", ",(0,t.jsx)(n.code,{children:"Float"}),", ",(0,t.jsx)(n.code,{children:"Double"}),", ",(0,t.jsx)(n.code,{children:"String"}),", ",(0,t.jsx)(n.code,{children:"ReadableArray"}),", ",(0,t.jsx)(n.code,{children:"ReadableMap"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["Annotation ",(0,t.jsx)(n.code,{children:"@ReactProp"})," has one obligatory argument ",(0,t.jsx)(n.code,{children:"name"})," of type ",(0,t.jsx)(n.code,{children:"String"}),". Name assigned to the ",(0,t.jsx)(n.code,{children:"@ReactProp"})," annotation linked to the setter method is used to reference the property on JS side."]}),"\n",(0,t.jsxs)(n.p,{children:["Except from ",(0,t.jsx)(n.code,{children:"name"}),", ",(0,t.jsx)(n.code,{children:"@ReactProp"})," annotation may take following optional arguments: ",(0,t.jsx)(n.code,{children:"defaultBoolean"}),", ",(0,t.jsx)(n.code,{children:"defaultInt"}),", ",(0,t.jsx)(n.code,{children:"defaultFloat"}),". Those arguments should be of the corresponding type (accordingly ",(0,t.jsx)(n.code,{children:"boolean"}),", ",(0,t.jsx)(n.code,{children:"int"}),", ",(0,t.jsx)(n.code,{children:"float"})," in Java and ",(0,t.jsx)(n.code,{children:"Boolean"}),", ",(0,t.jsx)(n.code,{children:"Int"}),", ",(0,t.jsx)(n.code,{children:"Float"}),' in Kotlin) and the value provided will be passed to the setter method in case when the property that the setter is referencing has been removed from the component. Note that "default" values are only provided for primitive types, in case when setter is of some complex type, ',(0,t.jsx)(n.code,{children:"null"})," will be provided as a default value in case when corresponding property gets removed."]}),"\n",(0,t.jsxs)(n.p,{children:["Setter declaration requirements for methods annotated with ",(0,t.jsx)(n.code,{children:"@ReactPropGroup"})," are different than for ",(0,t.jsx)(n.code,{children:"@ReactProp"}),", please refer to the ",(0,t.jsx)(n.code,{children:"@ReactPropGroup"})," annotation class docs for more information about it. ",(0,t.jsx)(n.strong,{children:"IMPORTANT!"}),' in ReactJS updating the property value will result in setter method call. Note that one of the ways we can update component is by removing properties that have been set before. In that case setter method will be called as well to notify view manager that property has changed. In that case "default" value will be provided (for primitive types "default" value can be specified using ',(0,t.jsx)(n.code,{children:"defaultBoolean"}),", ",(0,t.jsx)(n.code,{children:"defaultFloat"}),", etc. arguments of ",(0,t.jsx)(n.code,{children:"@ReactProp"})," annotation, for complex types setter will be called with value set to ",(0,t.jsx)(n.code,{children:"null"}),")."]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="Kotlin"',children:' @ReactProp(name = "src")\r\n fun setSrc(view: ReactImageView, sources: ReadableArray?) {\r\n view.setSource(sources)\r\n }\r\n\r\n @ReactProp(name = "borderRadius", defaultFloat = 0f)\r\n override fun setBorderRadius(view: ReactImageView, borderRadius: Float) {\r\n view.setBorderRadius(borderRadius)\r\n }\r\n\r\n @ReactProp(name = ViewProps.RESIZE_MODE)\r\n fun setResizeMode(view: ReactImageView, resizeMode: String?) {\r\n view.setScaleType(ImageResizeMode.toScaleType(resizeMode))\r\n }\n'})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="Java"',children:' @ReactProp(name = "src")\r\n public void setSrc(ReactImageView view, @Nullable ReadableArray sources) {\r\n view.setSource(sources);\r\n }\r\n\r\n @ReactProp(name = "borderRadius", defaultFloat = 0f)\r\n public void setBorderRadius(ReactImageView view, float borderRadius) {\r\n view.setBorderRadius(borderRadius);\r\n }\r\n\r\n @ReactProp(name = ViewProps.RESIZE_MODE)\r\n public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {\r\n view.setScaleType(ImageResizeMode.toScaleType(resizeMode));\r\n }\n'})})})]}),"\n",(0,t.jsxs)(n.h3,{id:"4-register-the-viewmanager",children:["4. Register the ",(0,t.jsx)(n.code,{children:"ViewM
1anager"})]}),"\n",(0,t.jsxs)(n.p,{children:["The final step is to register the ViewManager to the application, this happens in a similar way to ",(0,t.jsx)(n.a,{href:"/docs/0.82/legacy/native-modules-android",children:"Native Modules"}),", via the applications package member function ",(0,t.jsx)(n.code,{children:"createViewManagers"}),"."]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="Kotlin"',children:" override fun createViewManagers(\r\n reactContext: ReactApplicationContext\r\n ) = listOf(ReactImageManager(reactContext))\n"})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="Java"',children:" @Override\r\n public List<ViewManager> createViewManagers(\r\n ReactApplicationContext reactContext) {\r\n return Arrays.<ViewManager>asList(\r\n new ReactImageManager(reactContext)\r\n );\r\n }\n"})})})]}),"\n",(0,t.jsx)(n.h3,{id:"5-implement-the-javascript-module",children:"5. Implement the JavaScript module"}),"\n",(0,t.jsx)(n.p,{children:"The very final step is to create the JavaScript module that defines the interface layer between Java/Kotlin and JavaScript for the users of your new view. It is recommended for you to document the component interface in this module (e.g. using TypeScript, Flow, or plain old comments)."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tsx",metastring:'title="ImageView.tsx"',children:"import {requireNativeComponent} from 'react-native';\r\n\r\n/**\r\n * Composes `View`.\r\n *\r\n * - src: Array<{url: string}>\r\n * - borderRadius: number\r\n * - resizeMode: 'cover' | 'contain' | 'stretch'\r\n */\r\nexport default requireNativeComponent('RCTImageView');\n"})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"requireNativeComponent"})," function takes the name of the native view. Note that if your component needs to do anything more sophisticated (e.g. custom event handling), you should wrap the native component in another React component. This is illustrated in the ",(0,t.jsx)(n.code,{children:"MyCustomView"})," example below."]}),"\n",(0,t.jsx)(n.h2,{id:"events",children:"Events"}),"\n",(0,t.jsxs)(n.p,{children:["So now we know how to expose native view components that we can control freely from JS, but how do we deal with events from the user, like pinch-zooms or panning? When a native event occurs the native code should issue an event to the JavaScript representation of the View, and the two views are linked with the value returned from the ",(0,t.jsx)(n.code,{children:"getId()"})," method."]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="Kotlin"',children:'class MyCustomView(context: Context) : View(context) {\r\n ...\r\n fun onReceiveNativeEvent() {\r\n val event = Arguments.createMap().apply {\r\n putString("message", "MyMessage")\r\n }\r\n val reactContext = context as ReactContext\r\n reactContext\r\n .getJSModule(RCTEventEmitter::class.java)\r\n .receiveEvent(id, "topChange", event)\r\n }\r\n}\n'})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="Java"',children:'class MyCustomView extends View {\r\n ...\r\n public void onReceiveNativeEvent() {\r\n WritableMap event = Arguments.createMap();\r\n event.putString("message", "MyMessage");\r\n ReactContext reactContext = (ReactContext)getContext();\r\n reactContext\r\n .getJSModule(RCTEventEmitter.class)\r\n .receiveEvent(getId(), "topChange", event);\r\n }\r\n}\n'})})})]}),"\n",(0,t.jsxs)(n.p,{children:["To map the ",(0,t.jsx)(n.code,{children:"topChange"})," event name to the ",(0,t.jsx)(n.code,{children:"onChange"})," callback prop in JavaScript, register it by overriding the ",(0,t.jsx)(n.code,{children:"getExportedCustomBubblingEventTypeConstants"}
1)," method in your ",(0,t.jsx)(n.code,{children:"ViewManager"}),":"]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="Kotlin"',children:'class ReactImageManager : SimpleViewManager<MyCustomView>() {\r\n ...\r\n override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {\r\n return mapOf(\r\n "topChange" to mapOf(\r\n "phasedRegistrationNames" to mapOf(\r\n "bubbled" to "onChange"\r\n )\r\n )\r\n )\r\n }\r\n}\n'})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="Java"',children:'public class ReactImageManager extends SimpleViewManager<MyCustomView> {\r\n ...\r\n public Map getExportedCustomBubblingEventTypeConstants() {\r\n return MapBuilder.builder().put(\r\n "topChange",\r\n MapBuilder.of(\r\n "phasedRegistrationNames",\r\n MapBuilder.of("bubbled", "onChange")\r\n )\r\n ).build();\r\n }\r\n}\n'})})})]}),"\n",(0,t.jsx)(n.p,{children:"This callback is invoked with the raw event, which we typically process in the wrapper component to make a simpler API:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tsx",metastring:'{8-11,13-17} title="MyCustomView.tsx"',children:"import {useCallback} from 'react';\r\nimport {requireNativeComponent} from 'react-native';\r\n\r\nconst RCTMyCustomView = requireNativeComponent('RCTMyCustomView');\r\n\r\nexport default function MyCustomView(props: {\r\n // ...\r\n /**\r\n * Callback that is called continuously when the user is dragging the map.\r\n */\r\n onChangeMessage: (message: string) => unknown;\r\n}) {\r\n const onChange = useCallback(\r\n event => {\r\n props.onChangeMessage?.(event.nativeEvent.message);\r\n },\r\n [props.onChangeMessage],\r\n );\r\n\r\n return <RCTMyCustomView {...props} onChange={onChange} />;\r\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"integration-with-an-android-fragment-example",children:"Integration with an Android Fragment example"}),"\n",(0,t.jsxs)(n.p,{children:["In order to integrate existing Native UI elements to your React Native app, you might need to use Android Fragments to give you a more granular control over your native component than returning a ",(0,t.jsx)(n.code,{children:"View"})," from your ",(0,t.jsx)(n.code,{children:"ViewManager"}),". You will need this if you want to add custom logic that is tied to your view with the help of ",(0,t.jsx)(n.a,{href:"https://developer.android.com/guide/fragments/lifecycle",children:"lifecycle methods"}),", such as ",(0,t.jsx)(n.code,{children:"onViewCreated"}),", ",(0,t.jsx)(n.code,{children:"onPause"}),", ",(0,t.jsx)(n.code,{children:"onResume"}),". The following steps will show you how to do it:"]}),"\n",(0,t.jsx)(n.h3,{id:"1-create-an-example-custom-view",children:"1. Create an example custom view"}),"\n",(0,t.jsxs)(n.p,{children:["First, let's create a ",(0,t.jsx)(n.code,{children:"CustomView"})," class which extends ",(0,t.jsx)(n.code,{children:"FrameLayout"})," (the content of this view can be any view that you'd like to render)"]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="CustomView.kt"',children:'// replace with your package\r\npackage com.mypackage\r\n\r\nimport android.content.Context\r\nimport android.graphics.Color\r\nimport android.widget.FrameLayout\r\nimport android.widget.TextView\r\n\r\nclass CustomView(context: Context) : FrameLayout(context) {\r\n init {\r\n // set padding and background color\r\n setPadding(16,16,16,16)\r\n setBackgroundColor(Color.parseColor("#5FD3F3"))\r\n\r\n // add default text view\r\n addView(TextView(context).apply {\r\n text = "Welcome to Android Fragments with React Native."\r\n })\r\n }\r\n}\n'})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="CustomView.java"',children:'// replace with your package\r\npackage com.mypackage;\r\n\r\nimport android.content.Context;\r\nimport android.graphics.Color;\r\nimport android.widget.FrameLayout;\r\nimport android.widget.ImageView;\r\nimport android.widget.TextView;\r\n\r\nimport androidx.annotation.NonNull;\r\n\r\npublic class CustomView extends FrameLayout {\r\n public CustomView(@NonNull Context context) {\r\n super(context);\r\n // set padding and background color\r\n this.setPadding(16,16,16,16);
1\r\n this.setBackgroundColor(Color.parseColor("#5FD3F3"));\r\n\r\n // add default text view\r\n TextView text = new TextView(context);\r\n text.setText("Welcome to Android Fragments with React Native.");\r\n this.addView(text);\r\n }\r\n}\n'})})})]}),"\n",(0,t.jsxs)(n.h3,{id:"2-create-a-fragment",children:["2. Create a ",(0,t.jsx)(n.code,{children:"Fragment"})]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="MyFragment.kt"',children:"// replace with your package\r\npackage com.mypackage\r\n\r\nimport android.os.Bundle\r\nimport android.view.LayoutInflater\r\nimport android.view.View\r\nimport android.view.ViewGroup\r\nimport androidx.fragment.app.Fragment\r\n\r\n// replace with your view's import\r\nimport com.mypackage.CustomView\r\n\r\nclass MyFragment : Fragment() {\r\n private lateinit var customView: CustomView\r\n\r\n override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\r\n super.onCreateView(inflater, container, savedInstanceState)\r\n customView = CustomView(requireNotNull(context))\r\n return customView // this CustomView could be any view that you want to render\r\n }\r\n\r\n override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\r\n super.onViewCreated(view, savedInstanceState)\r\n // do any logic that should happen in an `onCreate` method, e.g:\r\n // customView.onCreate(savedInstanceState);\r\n }\r\n\r\n override fun onPause() {\r\n super.onPause()\r\n // do any logic that should happen in an `onPause` method\r\n // e.g.: customView.onPause();\r\n }\r\n\r\n override fun onResume() {\r\n super.onResume()\r\n // do any logic that should happen in an `onResume` method\r\n // e.g.: customView.onResume();\r\n }\r\n\r\n override fun onDestroy() {\r\n super.onDestroy()\r\n // do any logic that should happen in an `onDestroy` method\r\n // e.g.: customView.onDestroy();\r\n }\r\n}\n"})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="MyFragment.java"',children:"// replace with your package\r\npackage com.mypackage;\r\n\r\nimport android.os.Bundle;\r\nimport android.view.LayoutInflater;\r\nimport android.view.View;\r\nimport android.view.ViewGroup;\r\nimport androidx.fragment.app.Fragment;\r\n\r\n// replace with your view's import\r\nimport com.mypackage.CustomView;\r\n\r\npublic class MyFragment extends Fragment {\r\n CustomView customView;\r\n\r\n @Override\r\n public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {\r\n super.onCreateView(inflater, parent, savedInstanceState);\r\n customView = new CustomView(this.getContext());\r\n return customView; // this CustomView could be any view that you want to render\r\n }\r\n\r\n @Override\r\n public void onViewCreated(View view, Bundle savedInstanceState) {\r\n super.onViewCreated(view, savedInstanceState);\r\n // do any logic that should happen in an `onCreate` method, e.g:\r\n // customView.onCreate(savedInstanceState);\r\n }\r\n\r\n @Override\r\n public void onPause() {\r\n super.onPause();\r\n // do any logic that should happen in an `onPause` method\r\n // e.g.: customView.onPause();\r\n }\r\n\r\n @Override\r\n public void onResume() {\r\n super.onResume();\r\n // do any logic that should happen in an `onResume` method\r\n // e.g.: customView.onResume();\r\n }\r\n\r\n @Override\r\n public void onDestroy() {\r\n super.onDestroy();\r\n // do any logic that should happen in an `onDestroy` method\r\n // e.g.: customView.onDestroy();\r\n }\r\n}\n"})})})]}),"\n",(0,t.jsxs)(n.h3,{id:"3-create-the-viewmanager-subclass",children:["3. Create the ",(0,t.jsx)(n.code,{children:"ViewM
1anager"})," subclass"]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="MyViewManager.kt"',children:'// replace with your package\r\npackage com.mypackage\r\n\r\nimport android.view.Choreographer\r\nimport android.view.View\r\nimport android.view.ViewGroup\r\nimport android.widget.FrameLayout\r\nimport androidx.fragment.app.FragmentActivity\r\nimport com.facebook.react.bridge.ReactApplicationContext\r\nimport com.facebook.react.bridge.ReadableArray\r\nimport com.facebook.react.uimanager.ThemedReactContext\r\nimport com.facebook.react.uimanager.ViewGroupManager\r\nimport com.facebook.react.uimanager.annotations.ReactPropGroup\r\n\r\nclass MyViewManager(\r\n private val reactContext: ReactApplicationContext\r\n) : ViewGroupManager<FrameLayout>() {\r\n private var propWidth: Int? = null\r\n private var propHeight: Int? = null\r\n\r\n override fun getName() = REACT_CLASS\r\n\r\n /**\r\n * Return a FrameLayout which will later hold the Fragment\r\n */\r\n override fun createViewInstance(reactContext: ThemedReactContext) =\r\n FrameLayout(reactContext)\r\n\r\n /**\r\n * Map the "create" command to an integer\r\n */\r\n override fun getCommandsMap() = mapOf("create" to COMMAND_CREATE)\r\n\r\n /**\r\n * Handle "create" command (called from JS) and call createFragment method\r\n */\r\n override fun receiveCommand(\r\n root: FrameLayout,\r\n commandId: String,\r\n args: ReadableArray?\r\n ) {\r\n super.receiveCommand(root, commandId, args)\r\n val reactNativeViewId = requireNotNull(args).getInt(0)\r\n\r\n when (commandId.toInt()) {\r\n COMMAND_CREATE -> createFragment(root, reactNativeViewId)\r\n }\r\n }\r\n\r\n @ReactPropGroup(names = ["width", "height"], customType = "Style")\r\n fun setStyle(view: FrameLayout, index: Int, value: Int) {\r\n if (index == 0) propWidth = value\r\n if (index == 1) propHeight = value\r\n }\r\n\r\n /**\r\n * Replace your React Native view with a custom fragment\r\n */\r\n fun createFragment(root: FrameLayout, reactNativeViewId: Int) {\r\n val parentView = root.findViewById<ViewGroup>(reactNativeViewId)\r\n setupLayout(parentView)\r\n\r\n val myFragment = MyFragment()\r\n val activity = reactContext.currentActivity as FragmentActivity\r\n activity.supportFragmentManager\r\n .beginTransaction()\r\n .replace(reactNativeViewId, myFragment, reactNativeViewId.toString())\r\n .commit()\r\n }\r\n\r\n fun setupLayout(view: View) {\r\n Choreographer.getInstance().postFrameCallback(object: Choreographer.FrameCallback {\r\n override fun doFrame(frameTimeNanos: Long) {\r\n manuallyLayoutChildren(view)\r\n view.viewTreeObserver.dispatchOnGlobalLayout()\r\n Choreographer.getInstance().postFrameCallback(this)\r\n }\r\n })\r\n }\r\n\r\n /**\r\n * Layout all children properly\r\n */\r\n private fun manuallyLayoutChildren(view: View) {\r\n // propWidth and propHeight coming from react-native props\r\n val width = requireNotNull(propWidth)\r\n val height = requireNotNull(propHeight)\r\n\r\n view.measure(\r\n View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),\r\n View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY))\r\n\r\n view.layout(0, 0, width, height)\r\n }\r\n\r\n companion object {\r\n private const val REACT_CLASS = "MyViewManager"\r\n private const val COMMAND_CREATE = 1\r\n }\r\n}\n'})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="MyViewManager.java"',children:'// replace with your package\r\npackage com.mypackage;\r\n\r\nimport android.view.Choreographer;\r\nimport android.view.View;\r\nimport android.view.ViewGroup;\r\nimport android.widget.FrameLayout;\r\n\r\nimport androidx.annotation.NonNull;\r\nimport androidx.annotation.Nullable;\r\nimport androidx.fragment.app.FragmentActivity;\r\n\r\nimport com.facebook.react.bridge.ReactApplicationContext;\r\nimport com.facebook.react.bridge.ReadableArray;\r\nimport com.facebook.react.common.MapBuilder;\r\nimport com.facebook.react.uimanager.annotations.ReactProp;\r\nimport com.facebook.react.uimanager.annotations.ReactPropGroup;\r\nimport com.facebook.react.uimanager.ViewGroupManager;\r\nimport com.facebook.react.uimanager.ThemedReactContext;\r\n\r\nimport java.util.Map;\r\n\r\npublic class MyViewManager extends ViewGroupManager<FrameLayout>
1 {\r\n\r\n public static final String REACT_CLASS = "MyViewManager";\r\n public final int COMMAND_CREATE = 1;\r\n private int propWidth;\r\n private int propHeight;\r\n\r\n ReactApplicationContext reactContext;\r\n\r\n public MyViewManager(ReactApplicationContext reactContext) {\r\n this.reactContext = reactContext;\r\n }\r\n\r\n @Override\r\n public String getName() {\r\n return REACT_CLASS;\r\n }\r\n\r\n /**\r\n * Return a FrameLayout which will later hold the Fragment\r\n */\r\n @Override\r\n public FrameLayout createViewInstance(ThemedReactContext reactContext) {\r\n return new FrameLayout(reactContext);\r\n }\r\n\r\n /**\r\n * Map the "create" command to an integer\r\n */\r\n @Nullable\r\n @Override\r\n public Map<String, Integer> getCommandsMap() {\r\n return MapBuilder.of("create", COMMAND_CREATE);\r\n }\r\n\r\n /**\r\n * Handle "create" command (called from JS) and call createFragment method\r\n */\r\n @Override\r\n public void receiveCommand(\r\n @NonNull FrameLayout root,\r\n String commandId,\r\n @Nullable ReadableArray args\r\n ) {\r\n super.receiveCommand(root, commandId, args);\r\n int reactNativeViewId = args.getInt(0);\r\n int commandIdInt = Integer.parseInt(commandId);\r\n\r\n switch (commandIdInt) {\r\n case COMMAND_CREATE:\r\n createFragment(root, reactNativeViewId);\r\n break;\r\n default: {}\r\n }\r\n }\r\n\r\n @ReactPropGroup(names = {"width", "height"}, customType = "Style")\r\n public void setStyle(FrameLayout view, int index, Integer value) {\r\n if (index == 0) {\r\n propWidth = value;\r\n }\r\n\r\n if (index == 1) {\r\n propHeight = value;\r\n }\r\n }\r\n\r\n /**\r\n * Replace your React Native view with a custom fragment\r\n */\r\n public void createFragment(FrameLayout root, int reactNativeViewId) {\r\n ViewGroup parentView = (ViewGroup) root.findViewById(reactNativeViewId);\r\n setupLayout(parentView);\r\n\r\n final MyFragment myFragment = new MyFragment();\r\n FragmentActivity activity = (FragmentActivity) reactContext.getCurrentActivity();\r\n activity.getSupportFragmentManager()\r\n .beginTransaction()\r\n .replace(reactNativeViewId, myFragment, String.valueOf(reactNativeViewId))\r\n .commit();\r\n }\r\n\r\n public void setupLayout(View view) {\r\n Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {\r\n @Override\r\n public void doFrame(long frameTimeNanos) {\r\n manuallyLayoutChildren(view);\r\n view.getViewTreeObserver().dispatchOnGlobalLayout();\r\n Choreographer.getInstance().postFrameCallback(this);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Layout all children properly\r\n */\r\n public void manuallyLayoutChildren(View view) {\r\n // propWidth and propHeight coming from react-native props\r\n int width = propWidth;\r\n int height = propHeight;\r\n\r\n view.measure(\r\n View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),\r\n View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));\r\n\r\n view.layout(0, 0, width, height);\r\n }\r\n}\n'})})})]}),"\n",(0,t.jsxs)(n.h3,{id:"4-register-the-viewmanager-1",children:["4. Register the ",(0,t.jsx)(n.code,{children:"ViewManager"})]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="MyPackage.kt"',children:"// replace with your package\r\npackage com.mypackage\r\n\r\nimport com.facebook.react.ReactPackage\r\nimport com.facebook.react.bridge.ReactApplicationContext\r\nimport com.facebook.react.uimanager.ViewManager\r\n\r\nclass MyPackage : ReactPackage {\r\n ...\r\n override fun createViewManagers(\r\n reactContext: ReactApplicationContext\r\n ) = listOf(MyViewManager(reactContext))\r\n}\n"})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="MyPackage.java"',children:"// replace with your package\r\npackage com.mypackage;\r\n\r\nimport com.facebook.react.ReactPackage;\r\nimport com.facebook.react.bridge.ReactApplicationContext;\r\nimport com.facebook.react.uimanager.ViewManager;\r\n\r\nimport java.util.Arrays;\r\nimport java.util.List;\r\n\r\npublic class MyPackage implements ReactPackage {\r\n\r\n @Override\r\n public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {\r\n return Arrays.<ViewManager>asList(\r\n new MyViewManager(reactContext)\r\n );\r\n }\r\n\r\n}\n"})})})]}),"\n",(0,t.jsxs)(n.h3,{id:"5-register-the-package",children:["5. Register the ",(0,t.jsx)(n.code,{children:"Package"})]}),"\n",(0,t.jsxs)(o.A,{groupId:"android-language",queryString:!0,defaultValue:s.A.defaultAndroidLanguage,values:s.A.androidLanguages,children:[(0,t.jsx)(l.A,{value:"kotlin",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-kotlin",metastring:'title="MainApplication.kt"',children:"override fun getPackages(): List<ReactPackage> =\r\n PackageList(this).packages.apply {\r\n // Packages that cannot be autolinked yet can be added manually here, for example:\r\n // add(MyReactNativePackage())\r\n add(MyAppPackage())\r\n }\n"})})}),(0,t.jsx)(l.A,{value:"java",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-java",metastring:'title="MainApplication.java"',children:"@Override\r\nprotected List<ReactPackage> getPackages() {\r\n List<ReactPackage> packages = new PackageList(this).getPackages();\r\n // Packages that cannot be autolinked yet can be added manually here, for example:\r\n // packages.add(new MyReactNativePackage());\r\n packages.add(new MyAppPackage());\r\n return packages;\r\n}\n"})})})]}),"\n",(0,t.jsx)(n.h3,{id:"6-implement-the-javascript-module",children:"6. Implement the JavaScript module"}),"\n",(0,t.jsx)(n.p,{children:"I. Start with custom View manager:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tsx",metastring:'title="MyViewManager.tsx"',children:"import {requireNativeComponent} from 'react-native';\r\n\r\nexport const MyViewManager =\r\n requireNativeComponent('MyViewManager');\n"})}),"\n",(0,t.jsxs)(n.p,{children:["II. Then implement custom View calling the ",(0,t.jsx)(n.code,{children:"create"})," method:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tsx",metastring:'title="MyView.tsx"',children:"import {useEffect, useRef} from 'react';\r\nimport {\r\n PixelRatio,\r\n UIManager,\r\n findNodeHandle,\r\n} from 'react-native';\r\n\r\nimport {MyViewManager}
1 from './my-view-manager';\r\n\r\nconst createFragment = viewId =>\r\n UIManager.dispatchViewManagerCommand(\r\n viewId,\r\n // we are calling the 'create' command\r\n UIManager.MyViewManager.Commands.create.toString(),\r\n [viewId],\r\n );\r\n\r\nexport const MyView = () => {\r\n const ref = useRef(null);\r\n\r\n useEffect(() => {\r\n const viewId = findNodeHandle(ref.current);\r\n createFragment(viewId);\r\n }, []);\r\n\r\n return (\r\n <MyViewManager\r\n style={{\r\n // converts dpi to px, provide desired height\r\n height: PixelRatio.getPixelSizeForLayoutSize(200),\r\n // converts dpi to px, provide desired width\r\n width: PixelRatio.getPixelSizeForLayoutSize(200),\r\n }}\r\n ref={ref}\r\n />\r\n );\r\n};\n"})}),"\n",(0,t.jsxs)(n.p,{children:["If you want to expose property setters using ",(0,t.jsx)(n.code,{children:"@ReactProp"})," (or ",(0,t.jsx)(n.code,{children:"@ReactPropGroup"}),") annotation see the ",(0,t.jsx)(n.a,{href:"#imageview-example",children:"ImageView example"})," above."]})]})}function g(e={}){let{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}},11551(e,n,a){a.d(n,{Ay:()=>l,RM:()=>i});var r=a(62540),t=a(43023);let i=[];function o(e){let n={a:"a",admonition:"admonition",p:"p",...(0,t.R)(),...e.components};return(0,r.jsx)(n.admonition,{type:"info",children:(0,r.jsxs)(n.p,{children:["Native Module and Native Components are our stable technologies used by the legacy architecture.\nThey will be deprecated
1in the future when the New Architecture will be stable. The New Architecture uses ",(0,r.jsx)(n.a,{href:"https://github.com/reactwg/react-native-new-architecture/blob/main/docs/turbo-modules.md",children:"Turbo Native Module"})," and ",(0,r.jsx)(n.a,{href:"https://github.com/reactwg/react-native-new-architecture/blob/main/docs/fabric-native-components.md",children:"Fabric Native Components"})," to achieve similar results."]})})}function l(e={}){let{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(o,{...e})}):o(e)}},98263(e,n,a){a.d(n,{A:()=>l});var r=a(62540);a(63696);var t=a(11750),i=a(23865);function o({children:e,className:n,hidden:a}){return(0,r.jsx)("div",{role:"tabpanel",className:(0,t.A)("tabItem_wHwb",n),hidden:a,children:e})}function l({children:e,className:n,value:a}){let{selectedValue:t,lazy:s}=(0,i.uc)(),c=a===t;return!c&&s?null:(0,r.jsx)(o,{className:n,hidden:!c,children:e})}},77779(e,n,a){a.d(n,{A:()=>p});var r=a(62540);a(63696);var t=a(11750),i=a(46065),o=a(23865),l=a(45194),s=a(83029);function c({className:e}){let{selectedValue:n,selectValue:a,tabValues:i,block:s}=(0,o.uc)(),d=[],{blockElementScrollPositionUntilNextRender:u}=(0,l.a_)(),p=e=>{let r=e.currentTarget,t=i[d.indexOf(r)].value;t!==n&&(u(r),a(t))},m=e=>{let n=null;switch(e.key){case"Enter":p(e);break;case"ArrowRight":{let a=d.indexOf(e.currentTarget)+1;n=d[a]??d[0];break}case"ArrowLeft":{let a=d.indexOf(e.currentTarget)-1;n=d[a]??d[d.length-1]}}n?.focus()};return(0,r.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,t.A)("tabs",{"tabs--block":s},e),children:i.map(({value:e,label:a,attributes:i})=>(0,r.jsx)("li",{role:"tab",tabIndex:n===e?0:-1,"aria-selected":n===e,ref:e=>{d.push(e)},onKeyDown:m,onClick:p,...i,className:(0,t.A)("tabs__item","tabItem_l0OV",i?.className,{"tabs__item--active":n===e}),children:a??e},e))})}function d({children:e}){return(0,r.jsx)("div",{className:"margin-top--md",children:e})}function u({className:e,children:n}){return(0,r.jsxs)("div",{className:(0,t.A)(i.G.tabs.container,"tabs-container","tabList_J5MA"),children:[(0,r.jsx)(c,{className:e}),(0,r.jsx)(d,{children:n})]})}function p(e){let n=(0,s.A)(),a=(0,o.OC)(e);return(0,r.jsx)(o.O_,{value:a,children:(0,r.jsx)(u,{className:e.className,children:(0,o.vT)(e.children)})},String(n))}},23865(e,n,a){a.d(n,{OC:()=>p,O_:()=>g,uc:()=>h,vT:()=>d});var r=a(62540),t=a(63696),i=a(49519),o=a(6743),l=a(88511),s=a(15396),c=a(89030);function d(e){return t.Children.toArray(e).filter(e=>"\n"!==e)}function u({value:e,tabValues:n}){return n.some(n=>n.value===e)}function p(e){let n,{defaultValue:a,queryString:r=!1,groupId:d}=e,p=function(e){let{values:n,children:a}=e;return(0,t.useMemo)(()=>{let e=n??t.Children.toArray(a).flatMap(e=>{if(!e)return[];if((0,t.isValidElement)(e)&&function(e){let{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return[e];let n="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${n}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop. 2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:n,attributes:a,default:r}})=>({value:e,label:n,attributes:a,default:r})),r=(0,s.XI)(e,(e,n)=>e.value===n.value);if(r.length>0)throw Error(`Docusaurus error: Duplicate values "${r.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[n,a])}(e),[m,h]=(0,t.useState)(()=>(function({defaultValue:e,tabValues:n}){if(0===n.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!u({value:e,tabValues:n}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${n.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let a=n.find(e=>e.default)??n[0];if(!a)throw Error("Unexpected error: 0 tabValues");return a.value})({defaultValue:a,tabValues:p})),[g,v]=function({queryString:e=!1,groupId:n}){let a=(0,i.W6)(),r=function({queryString:e=!1,groupId:n}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!n)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:e,groupId:n});return[(0,l.aZ)(r),(0,t.useCallback)(e=>{if(!r)return;let n=new URLSearchParams(a.location.search);n.set(r,e),a.replace({...a.location,search:n.toString()})},[r,a])]}({queryString:r,groupId:d}),[w,x]=function({groupId:e}){let n=e?`docusaurus.tab.${e}`:null,[a,r]=(0,c.Dv)(n);return[a,(0,t.useCallback)(e=>{n&&r.set(e)},[n,r])]}({groupId:d}),f=u({value:n=g??w,tabValues:p})?n:null;return(0,o.A)(()=>{f&&h(f)},[f]),{selectedValue:m,selectValue:(0,t.useCallback)(e=>{if(!u({value:e,tabValues:p}))throw Error(`Can't select invalid tab value=${e}`);h(e),v(e),x(e)},[v,x,p]),tabValues:p,lazy:e.lazy??!1,block:e.block??!1}}let m=(0,t.createContext)(null);function h(){let e=t.useContext(m);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function g(e){return(0,r.jsx)(m.Provider,{value:e.value,children:e.children})}},38469(e,n,a){a.d(n,{A:()=>o});var r=a(93227);let t=!!r.A.canUseDOM&&navigator.platform.startsWith("Mac"),i=!!r.A.canUseDOM&&navigator.platform.startsWith("Win"),o={defaultGuide:"quickstart",defaultJsDebugger:"flipper",defaultOs:t?"macos":i?"windows":"linux",defaultPackageManager:"npm",defaultPlatform:t?"ios":"android",defaultSyntax:"functional",defaultAndroidLanguage:"java",defaultAppleLanguage:"objc",defaultJavaScriptSpecLanguages:"typescript",getDevNotesTabs:(e=["android","ios","web","windows"])=>[e.includes("android")?{label:"Android",value:"android"}:void 0,e.includes("ios")?{label:"iOS",value:"ios"}:void 0,e.includes("web")?{label:"Web",value:"web"}:void 0,e.includes("windows")?{label:"Windows",value:"windows"}
2:void 0].filter(Boolean),guides:[{label:"Expo Go Quickstart",value:"quickstart"},{label:"React Native CLI Quickstart",value:"native"}],oses:[{label:"macOS",value:"macos"},{label:"Windows",value:"windows"},{label:"Linux",value:"linux"}],packageManagers:[{label:"npm",value:"npm"},{label:"Yarn",value:"yarn"}],platforms:[{label:"Android",value:"android"},{label:"iOS",value:"ios"}],syntax:[{label:"Function Component",value:"functional"},{label:"Class Component",value:"classical"}],androidLanguages:[{label:"Java",value:"java"},{label:"Kotlin",value:"kotlin"}],appleLanguages:[{label:"ObjectiveC",value:"objc"},{label:"Swift",value:"swift"}],javaScriptSpecLanguages:[{label:"TypeScript",value:"typescript"},{label:"Flow",value:"flow"}],jsDebuggers:[{label:"Hermes Debugger / Expo",value:"hermes"},{label:"Flipper",value:"flipper"},{label:"New Debugger (Experimental)",value:"new-debugger"}],snackLanguages:[{label:"TypeScript",value:"typescript"},{label:"JavaScript",value:"javascript"}],defaultSnackLanguage:"typescript"}},43023(e,n,a){a.d(n,{R:()=>o,x:()=>l});var r=a(63696);let t={},i=r.createContext(t);function o(e){let n=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:o(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.