Movatterモバイル変換


[0]ホーム

URL:


Get in touch

Article

Introduction to SwiftUI for NativeScript

Introduction to SwiftUI for NativeScript, photo 0 - Valor Software
Douglas Machado
JS Developer
Fri Dec 23 2022
Introduction to SwiftUI for NativeScript, photo 1 - Valor Software

Building user interfaces declaratively is something the Web community has widely adopted, and nowadays, large applications are built following these principles. For example, Google launchedJetpack Compose, and Apple announcedSwiftUI atWWDC19, receiving an immensely positive response from developers.

Here atValor Software, we are always excited about new advancements in development technologies, and we are fans of NativeScript. We collaborated withnStudio to provide an effective and enjoyable SwiftUI integration for iOS apps driven by NativeScript.

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

Prerequisites

  • macOS Catalina or higher

  • Xcode 11 or higher

  • iOS device/simulator running iOS 13 or higher

SwiftUI Concepts

Modern iOS development is primarily done using the Swift programming language. SwiftUI uses a declarative syntax—you state what your user interface should do.

I recommend taking the officialSwiftUI tour, to get familiar with the basic concepts

Create a NativeScript app

We can create an app using a standard TypeScript template:

ns create swiftui --tscd swiftui

This will setup what is often called a "vanilla" flavored NativeScript app. In other words, it provides basic data binding capabilities and a rather simple setup. However, what we will cover here applies to any flavor (Angular, React, Svelte, Vue, etc.). You can explore more via StackBlitz from the following:

  • JavaScript starter

  • TypeScript starter

  • Angular starter

  • React starter

  • Svelte starter

  • Vue starter

SwiftUI Plugin

Install the SwiftUI plugin:

npm install @nativescript/swift-ui
Note
Your minimum iOS deployment target should be at least 13.

You can add this line toApp_Resources/iOS/build.xcconfig:

IPHONEOS_DEPLOYMENT_TARGET = 13.0;

SwiftUI Usage

  1. Create your SwiftUI

    Create App_Resources/iOS/src/SampleView.swift:

    import SwiftUIstruct SampleView: View {  var body: some View {    VStack {      Text("Hello World")        .padding()    }  }}
  2. Create your SwiftUI Provider

    This will prepare your SwiftUI for two-way data bindings to NativeScript.

    CreateApp_Resources/iOS/src/SampleViewProvider.swift:

    import SwiftUI@objcclass SampleViewProvider: UIViewController, SwiftUIProvider {  // MARK: INIT  required init?(coder aDecoder: NSCoder) {    super.init(coder: aDecoder)  }  required public init() {    super.init(nibName: nil, bundle: nil)  }  public override func viewDidLoad() {    super.viewDidLoad()    setupSwiftUIView(content: swiftUIView)  }  // MARK: PRIVATE  private var swiftUIView = SampleView()  /// Receive data from NativeScript  func updateData(data: NSDictionary) {      // can be empty  }  /// Allow sending of data to NativeScript  var onEvent: ((NSDictionary) -> ())?}
  3. Insert into any NativeScript layout

    app/main-page.xml

    <Pagexmlns="http://schemas.nativescript.org/tns.xsd"xmlns:sw="@nativescript/swift-ui"class="page"><StackLayout><sw:SwiftUI swiftId="sampleView" height="100" /></StackLayout></Page>
  4. Register your SwiftUI via the swiftId

    This can be done in the NativeScript app’s bootstrap file (often app.ts or main.ts).

    • app.ts

      import {registerSwiftUI,UIDataDriver} from "@nativescript/swift-ui";// A. You can generate types for your own Swift Provider with 'ns typings ios'// B. Otherwise you can ignore by declaring the class name you know you provideddeclare const SampleViewProvider: any;registerSwiftUI("sampleView", (view) =>new UIDataDriver(SampleViewProvider.alloc().init(), view));

      You can now run the app with ns debug ios.

Use Xcode to develop your SwiftUI

After running the project once, you can open it in Xcode to further develop your SwiftUI using all the convenient aid of Xcode intellisense.

For example from the root of your project:

open platforms/ios/swiftui.xcworkspace

You will find your .swift code underneath the TNSNativeSource folder as seen here…​

Introduction to SwiftUI for NativeScript, photo 2 - Valor Software

iOS Preview

Introduction to SwiftUI for NativeScript, photo 3 - Valor Software

Advanced SwiftUI Integration

Let’s dive deeper by hooking up data bindings + events between SwiftUI and NativeScript.

Create the SwiftUI component

This can be any SwiftUI you would like to use in NativeScript.

CreateApp_Resources/iOS/src/SampleView.swift:

import SwiftUIclass ButtonProps: ObservableObject {  @Published var count: Int = 0  var incrementCount: (() -> Void)?}struct SampleView: View {  @ObservedObject var props = ButtonProps()  var body: some View {      VStack(alignment: .center, spacing: 0) {          HStack(alignment:.center) {              Text("Count (props.count)")                  .padding()                  .scaledToFill()                  .minimumScaleFactor(0.5)          }          HStack(alignment: .center) {              Button(action: {                  self.props.incrementCount?()              }) {                  Image(systemName: "plus.circle.fill")                      .foregroundColor(.white)                      .padding()                      .background(LinearGradient(                          gradient: Gradient(                              colors: [Color.purple, Color.pink]), startPoint: .top, endPoint: .bottom                      ))                      .clipShape(Circle())              }          }      }      .padding()      .clipShape(Circle())  }}

CreateApp_Resources/iOS/src/SampleViewProvider.swift:

import SwiftUI@objcclass SampleViewProvider: UIViewController, SwiftUIProvider {  // MARK: INIT  required init?(coder aDecoder: NSCoder) {    super.init(coder: aDecoder)  }  required public init() {    super.init(nibName: nil, bundle: nil)  }  public override func viewDidLoad() {    super.viewDidLoad()    setupSwiftUIView(content: swiftUIView)    registerObservers()  }  // MARK: PRIVATE  private var swiftUIView = SampleView()  private func registerObservers() {    swiftUIView.props.incrementCount = {      let count = self.swiftUIView.props.count + 1      // update swiftUI view      self.swiftUIView.props.count = count      // notify nativescript      self.onEvent?(["count": count])    }  }  // MARK: API  /// Receive data from NativeScript  func updateData(data: NSDictionary) {    if let count = data.value(forKey: "count") as? Int {      // update swiftUI view      swiftUIView.props.count = count      // notify nativescript      self.onEvent?(["count": count])    }  }  /// Send data to NativeScript  var onEvent: ((NSDictionary) -> Void)?}

Use your SwiftUI in a NativeScript layout

  • app/main-page.xml:

<Page  xmlns="http://schemas.nativescript.org/tns.xsd"  xmlns:sw="@nativescript/swift-ui"  navigatingTo="navigatingTo">  <StackLayout>    <sw:SwiftUI swiftId="sampleView" data="{{ nativeCount }}" swiftUIEvent="{{ onEvent }}" loaded="{{ loadedSwiftUI }}" />    <Label text="{{ 'NativeScript Label: ' + nativeCount.count }}" />    <Button text="NativeScript data bindings: Decrement" tap="{{ updateNativeScriptData }}" />    <Button text="SwiftUI data bindings: Decrement" tap="{{ updateSwiftData }}" />  </StackLayout></Page>
  • app/main-page.ts:

import {  registerSwiftUI,  UIDataDriver,  SwiftUI,  SwiftUIEventData,} from "@nativescript/swift-ui";import {  EventData,  Observable,  Page} from "@nativescript/core";// A. You can generate types for your own Swift Provider with 'ns typings ios'// B. Otherwise you can ignore by declaring the class name you know you provideddeclare const SampleViewProvider: any;registerSwiftUI("sampleView", (view) =>  new UIDataDriver(SampleViewProvider.alloc().init(), view));interface CountData {  count: number;}export function navigatingTo(args: EventData) {  const page = <Page>args.object;  page.bindingContext = new DemoModel();}export class DemoModel extends Observable {  swiftui: SwiftUI;  nativeCount = {    count: 0,  };  loadedSwiftUI(args) {    this.swiftui = args.object;  }  onEvent(evt: SwiftUIEventData<CountData>) {    this.set("nativeCount", { count: evt.data.count });  }  updateNativeScriptData() {    this.set('nativeCount', { count: this.nativeCount.count - 1 });  }  updateSwiftData() {    this.swiftui.updateData({ count: this.nativeCount.count - 1 });  }}

iOS screen

More Articles


[8]ページ先頭

©2009-2025 Movatter.jp