Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Introduction to Jetpack Compose for NativeScript
Valor Labs profile imageEduardo Speroni
Eduardo Speroni forValor Labs

Posted on • Edited on

     

Introduction to Jetpack Compose for NativeScript

Building user interfaces declaratively is something the Web community has widely adopted, and nowadays, large applications are built following these principles. For example, Google launched Jetpack Compose, and Apple announced SwiftUI at WWDC19, receiving an immensely positive response from developers.

Here at Valor Software, we are always excited about new advancements in development technologies, and we are fans of NativeScript. We collaborated with nStudio to provide an effective and enjoyable Jetpack Compose integration for Android apps driven by NativeScript.

Earlier this month we announcedSwiftUI for NativeScript, which follow the same principles and API design as Jetpack Compose for NativeScript.

In this article, we'll demonstrate how to use Jetpack Compose within NativeScript to explore fun new possibilities in building amazing UIs together.

Create a NativeScript app

We can create an app using a standard TypeScript template:

ns create jetpackcompose--tscdjetpackcompose
Enter fullscreen modeExit fullscreen mode

This will setup what is often called a "vanilla" flavored NativeScript app. You can use whichever flavor you're most comfortable with, though. Setting the plugin up for Angular (and most other flavors) is usually a case of registering the view, which we'll demonstrate in a section below.

Install the Jetpack Compose plugin:

npminstall @nativescript/jetpack-compose
Enter fullscreen modeExit fullscreen mode

Note: Jetpack Compose requires you to use at least API 21 (Lollipop) as your minimum SDK version. You can do this by addingminSdkVersion 21 to your app.gradle.

If you plan to build your libraries directly from Android Studio, you don't need anything else, just drop your built.aar inApp_Resources/Android/libs/ and skip to the next section. But if you're planning on writing Kotlin code directly in.kt files inApp_Resources/Android/src/main/java, then we need some extra steps.

First, add your compose dependencies inapp.gradle:

dependencies{defcompose_version="1.2.1"implementation"androidx.compose.ui:ui:$compose_version"// Tooling support (Previews, etc.)implementation"androidx.compose.ui:ui-tooling:$compose_version"// Add any other dependencies your Jetpack Compose UI needs// like material design:// implementation 'androidx.compose.material:material:$compose_version'}
Enter fullscreen modeExit fullscreen mode

Then modify theandroid section so you enable compose:

android{// other settings like targetSdk, etc.buildFeatures{composetrue}compileOptions{sourceCompatibilityJavaVersion.VERSION_1_8targetCompatibilityJavaVersion.VERSION_1_8}kotlinOptions{jvmTarget="1.8"}composeOptions{kotlinCompilerExtensionVersion'1.3.2'}}
Enter fullscreen modeExit fullscreen mode

And finally, enable Kotlin by creating the fileApp_Resources/Android/gradle.properties

useKotlin=truekotlinVersion=1.7.20 # you can choose your kotlin version here
Enter fullscreen modeExit fullscreen mode

Jetpack Compose usage

A. Create your Jetpack Compose views and wrapper

CreateApp_Resources/Android/src/main/java/BasicView.kt:

packagecom.exampleimportandroid.content.Contextimportandroidx.compose.material.MaterialThemeimportandroidx.compose.material.Textimportandroidx.compose.runtime.Composableimportandroidx.compose.runtime.getValueimportandroidx.compose.runtime.mutableStateOfimportandroidx.compose.runtime.setValueimportandroidx.compose.ui.platform.ComposeViewimportandroidx.lifecycle.ViewModelimportandroidx.lifecycle.viewmodel.compose.viewModelclassBasicView{fungenerateComposeView(view:ComposeView):ComposeView{returnview.apply{setContent{MaterialTheme{Text("Hello from Jetpack Compose")}}}}funupdateData(value:Map<Any,Any>){}varonEvent:((String)->Unit)?=null}
Enter fullscreen modeExit fullscreen mode

To use the default plugin handling of Compose views, it's important that your implementation follows the following interface:

classExample{fungenerateComposeView(view:ComposeView):ComposeView{// render your compose views into the ComposeView}funupdateData(value:Map<Any,Any>){// this function receives data from NativeScript// value is a js object converted to a map}// this is the event you will send back to Jetpack Compose// when you need to pass data, just call onEvent?.invoke(v)varonEvent:((Any)->Unit)?=null}
Enter fullscreen modeExit fullscreen mode

B. Register your Jetpack Compose via thecomposeId

This can be done in the NativeScript app's bootstrap file (oftenapp.ts ormain.ts).

import{registerJetpackCompose,ComposeDataDriver}from'@nativescript/jetpack-compose';// A. You can generate types for your own Compose Provider with 'ns typings android --aar {path/to/{name}.aar}'// B. Otherwise you can ignore by declaring the package resolution path you know you provideddeclarevarcom;registerJetpackCompose('sampleView',(view)=>newComposeDataDriver(newcom.example.BasicView(),view));
Enter fullscreen modeExit fullscreen mode

Additionally, if you want to use Angular, you can register the compose view itself:

import{registerElement}from'@nativescript/angular';import{JetpackCompose}from'@nativescript/jetpack-compose';registerElement('JetpackCompose',()=>JetpackCompose)
Enter fullscreen modeExit fullscreen mode

C. Insert into any NativeScript layout

app/main-page.xml

<Pagexmlns="http://schemas.nativescript.org/tns.xsd"xmlns:jc="@nativescript/jetpack-compose"class="page"><StackLayout><jc:JetpackComposecomposeId="sampleView"height="100"/></StackLayout></Page>
Enter fullscreen modeExit fullscreen mode

You can now run the app withns debug android.

Use Android Studio to develop and preview Jetpack Compose

After running the app once you can open theplatforms/android folder in Android Studio where you'll be able to find theBasicView.kt file. From there you can start modifying it and previewing your changes (by adding the@Preview decorator on the@Composable you want to preview).

Important: Saving this file will not change theBasicView.kt that lives inside yourApp_Resources, so be VERY careful to copy the file contents back once you're done editing it! This will become a DX improvement in the future.

Alternatively, you cancreate a new Android library and develop all your Jetpack Compose views there.

Sending and receiving data to/from NativeScript

First, let's add some bindings to our BasicView so it now receives data inupdateData and displays that, as well as output an event once the data is updated:

packagecom.exampleimportandroid.content.Contextimportandroidx.compose.material.MaterialThemeimportandroidx.compose.material.Textimportandroidx.compose.runtime.Composableimportandroidx.compose.runtime.getValueimportandroidx.compose.runtime.mutableStateOfimportandroidx.compose.runtime.setValueimportandroidx.compose.ui.platform.ComposeViewimportandroidx.lifecycle.ViewModelimportandroidx.lifecycle.viewmodel.compose.viewModelclassBasicView{data classExampleUiState(valtext:String=""){}classExampleViewModel():ViewModel(){varuiStatebymutableStateOf(ExampleUiState())}varmViewModel=ExampleViewModel()fungenerateComposeView(view:ComposeView):ComposeView{returnview.apply{setContent{MaterialTheme{valuiState=mViewModel.uiState;// In Compose worldText(uiState.text)}}}}funupdateData(value:Map<Any,Any>){valv=value["data"]asString;onEvent?.invoke(v)mViewModel.uiState=ExampleUiState(v);}varonEvent:((String)->Unit)?=null}
Enter fullscreen modeExit fullscreen mode

Use your Jetpack Compose in a NativeScript layout

app/main-page.xml:

<Pagexmlns="http://schemas.nativescript.org/tns.xsd"navigatingTo="navigatingTo"class="page"xmlns:jc="@nativescript/jetpack-compose"><StackLayout><Labeltext="The following view is Jetpack Compose inside NativeScript!"textWrap="true"></Label><jc:JetpackComposecomposeEvent="{{ onEvent }}"data="{{ text }}"composeId="sampleView"></sw:JetpackCompose><Labeltext="This is NativeScript again"></Label><TextViewtextChange="{{ onTextChange }}"text="{{ text }}"textWrap="true"></TextView></StackLayout></Page>
Enter fullscreen modeExit fullscreen mode

app/main-page.ts:

import{Observable}from'@nativescript/core';import{registerJetpackCompose,ComposeDataDriver}from'@nativescript/jetpack-compose';import{EventData,Page,PropertyChangeData}from'@nativescript/core';// A. You can generate types for your own Compose Provider with 'ns typings android --aar {path/to/{name}.aar}'// B. Otherwise you can ignore by declaring the package resolution path you know you provideddeclarevarcom;registerJetpackCompose('sampleView',(view)=>newComposeDataDriver(newcom.example.BasicView(),view));exportfunctionnavigatingTo(args:EventData){constpage=<Page>args.object;page.bindingContext=newDemoModel();}exportclassDemoModelextendsObservable{text='';onEvent(evt:JetpackComposeEventData<string>){console.log('onEvent',evt.data);}onTextChange(evt:PropertyChangeData){console.log('textChange',evt.value);this.set('text',evt.value);}}
Enter fullscreen modeExit fullscreen mode

Now every time you change the text on the NativeScriptTextView it'll update the text on the Jetpack Compose view!

ColorPicker example

Here's another example where I use a ColorPicker to change a NativeScript view's background color:

app.gradle

implementation"com.github.skydoves:colorpicker-compose:1.0.0"
Enter fullscreen modeExit fullscreen mode
packagecom.exampleimportandroid.content.Contextimportandroidx.compose.foundation.layout.fillMaxSizeimportandroidx.compose.foundation.layout.fillMaxWidthimportandroidx.compose.foundation.layout.heightimportandroidx.compose.foundation.layout.paddingimportandroidx.compose.material.MaterialThemeimportandroidx.compose.material.Textimportandroidx.compose.runtime.Composableimportandroidx.compose.runtime.getValueimportandroidx.compose.runtime.mutableStateOfimportandroidx.compose.runtime.setValueimportandroidx.compose.ui.Modifierimportandroidx.compose.ui.graphics.Colorimportandroidx.compose.ui.graphics.ImageBitmapimportandroidx.compose.ui.platform.ComposeViewimportandroidx.compose.ui.res.imageResourceimportandroidx.compose.ui.unit.dpimportandroidx.lifecycle.ViewModelimportandroidx.lifecycle.viewmodel.compose.viewModelimportcom.github.skydoves.colorpicker.compose.ColorEnvelopeimportcom.github.skydoves.colorpicker.compose.HsvColorPickerimportcom.github.skydoves.colorpicker.compose.ImageColorPickerimportcom.github.skydoves.colorpicker.compose.rememberColorPickerControllerclassColorPickerCompose{fungenerateComposeView(view:ComposeView):ComposeView{returnview.apply{setContent{valcontroller=rememberColorPickerController()HsvColorPicker(modifier=Modifier.fillMaxWidth().height(450.dp).padding(10.dp),controller=controller,onColorChanged={colorEnvelope:ColorEnvelope->onEvent?.invoke(colorEnvelope.hexCode)})}}}funupdateData(value:Map<Any,Any>){}varonEvent:((String)->Unit)?=null}
Enter fullscreen modeExit fullscreen mode
<StackLayoutbackgroundColor="{{ backgroundColor }}"><Labeltext="The following view is Jetpack Compose inside NativeScript!"textWrap="true"></Label><StackLayoutbackgroundColor="lightblue"><jc:JetpackComposecomposeEvent="{{ onEvent }}"data="{{ text }}"composeId="jetpackCompose"></sw:JetpackCompose></StackLayout><Labeltext="This is NativeScript again"></Label><TextViewtext="{{ backgroundColor }}"textWrap="true"></TextView></StackLayout>
Enter fullscreen modeExit fullscreen mode

Final considerations

Working with Jetpack Compose in NativeScript is very transparent and easy. We look forward in seeing what the community will build with yet another powerful tool in NativeScript's belt!

About Valor Software:

Official NativeScript professional support partner, Valor is actively contributing to the NativeScript ecosystem, providing enterprise support, consulting, and team augmentation. Valor Software additionally helps with all aspects of the SDLC, web, backend and mobile. Book acall today or email us atsales@valor-software.com if you need help.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Modernizing the web with Module Federation and Nx

More fromValor Labs

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp