繁体   English   中英

如何使用原生 SwiftUI 查看 NativeScript 7

[英]How to use a native SwiftUI View in NativeScript 7

在我的 NativeScript (Angular) 应用程序中,我使用 RadListView 创建一个列表,每个元素都有许多不同的信息要显示。 看起来像这样

样本对象列表

由于 Stackoverflow 和其他来源的许多提示,我尽可能减少了嵌套布局(StackLayout、GridLayout、...)的数量,以使 RadListView 更快。 在 Android 上,使用列表的性能比在 iOS 上要好得多。 使用 iPad Pro (2020) 时,列表在滚动时的呈现不流畅。 如果用户更改设备的方向,屏幕会冻结,并且会在侧面或底部出现片刻黑条。 冻结的时间取决于每行中显示的元素数量。 ListView 中的相同行布局要快得多,但与原生 (SwiftUI) 不同,并且缺少滑动和拉动刷新等功能。

对不起歌词,但我认为有一点背景可以解释为什么我尝试下一步。

为了改善用户体验,我使用 SwiftUI 和几乎相同的行布局制作了一个小型原生测试应用程序。 感觉好多了,首次加载速度快,滚动流畅,没有方向变化的延迟。 我的下一个想法是在 SwiftUI 中创建一个本机组件,以尽可能显示/渲染 RadListView 的每一行

<RadListView [items]="items">
    <ListViewLinearLayout tkListViewLayout></ListViewLinearLayout>
    <ng-template tkListItemTemplate let-item="item" let-i="index" let-odd="odd">
        <MyNativeSwiftUIComponentElement data="item.rowData"></MyNativeSwiftUIComponentElement>
    </ng-template>
</RadListView>

或使用 SwiftUI 中的列表来显示/渲染整个列表

<ActionBar title="Objects"></ActionBar>
<MyNativeSwiftUIListComponent data="items"></MyNativeSwiftUIListComponent>

寻找文档和示例很困难。 I found this very short advise Adding Objective-C/Swift code and the linked tutorial there for Objective-C ( Adding Objective-C Code to a NativeScript App ) and some questions on Stackoverflow but there all about classes and not SwiftUI (with struct and views). One question was about SwiftUI: Is it possible to display a View written with SwiftUI with NativeScript the answer was unfortunately not helpful for me (btw. thank you @Manoj for your great support for NativeScript at Stackoverflow.).

如何在我的 {N} 应用程序中使用 SwiftUI View 作为本机组件? 有没有人提示、教程链接或应用程序/插件的公共存储库链接? 欢迎每一个小提示。

您也许可以使用 Nativescript 的placeholder组件(更多信息请点击此处

所以你会在你的模板上有Placeholder标签,并使用creatingView事件来添加本机 UI

<Placeholder creatingView="creatingView"/>
import { CreateViewEventData } from "@nativescript/core";

export function creatingView(args: CreateViewEventData) {
    let nativeView = new UILabel();  // where this would be your native UI
    nativeView.text = "Native";
    args.view = nativeView;
}

过了一会儿,我放弃了在项目({N}+Angular)中直接使用 SwiftUI 的尝试,而是尝试了@William-Juan 建议的<Placeholder>组件。 但看起来,Angular 风格中未官方支持<Placeholder> - 请参阅github 问题 #283

继续前进,我查看了 NativeScript 插件的示例并构建了一个可行的解决方案。 如果有人对完整示例源代码感兴趣,请在此存储库中: https://github.com/teha-at/sample-nativescript-native-ui-component

首先,创建一个 class 扩展@nativescript/core/View class 并有一个项目来获取将要显示的数据。

// object-list-item.d.ts
// [...]
export class ObjectListItem extends View {
    item: ObjectModel;
}

export const itemProperty: Property<ObjectListItem, string>;

然后创建一个抽象基础 class ,它还扩展了@nativescript/core/View class ,这为 Android 和 Z1BZDF155991920CDB1DZ 创建了基础

// object-list-item.common.ts
// [...]

export const itemProperty = new Property<ObjectListItemBase, string>({
    name: 'item',
    defaultValue: null,
    affectsLayout: isIOS,
});

export abstract class ObjectListItemBase extends View {
    item: PortalObjectModel;
}

// defines 'item' property on the ObjectListItemBase class
itemProperty.register(ObjectListItemBase);

ObjectListItemBase.prototype.recycleNativeView = 'auto';

因为我只是在寻找 iOS 的组件,所以object-list-item.android.ts非常简单:

// object-list-item.android.ts
import { ObjectListItemBase } from './object-list-item.common';
export class ObjectListItem extends ObjectListItemBase {}

对于 iOS 有更多的行,完整的文件内容请查看github repo

/// object-list-item.ios.ts
// [...]

export class ObjectListItem extends ObjectListItemBase {

    // added for TypeScript intellisense.
    nativeView: UIView;
    
    // [...]

    /**
     * Creates new native button.
     */
    public createNativeView(): Object {
        const mainUiStackView = UIStackView.new();
    // [...]
    }

    /**
     * Initializes properties/listeners of the native view.
     */
    initNativeView(): void {
        // Attach the owner to nativeView.
        // When nativeView is tapped we get the owning JS object through this field.
        (<any>this.nativeView).owner = this;
        super.initNativeView();
    }

    /**
     * Clean up references to the native view and resets nativeView to its original state.
     * If you have changed nativeView in some other way except through setNative callbacks
     * you have a chance here to revert it back to its original state
     * so that it could be reused later.
     */
    disposeNativeView(): void {
        // Remove reference from native listener to this instance.
        (<any>this.nativeView).owner = null;

        // If you want to recycle nativeView and have modified the nativeView
        // without using Property or CssProperty (e.g. outside our property system - 'setNative' callbacks)
        // you have to reset it to its initial state here.
        super.disposeNativeView();
    }

    [itemProperty.setNative](item: ObjectModel) {
        this.item = item;
        // [...]
    }

}

添加 Angular 指令

// object-list-item.directives.ts
@Directive({
    selector: 'ObjectListItem',
})
export class ObjectListItemDirective {
}

export const ObjectListItemDirectives = [ObjectListItemDirective];

至少在 Angular 模块中注册该组件。

// object-list-item.module.ts
// [...]

@NgModule({
    imports: [],
    declarations: [
        ObjectListItemDirectives,
    ],
    schemas: [NO_ERRORS_SCHEMA],
    exports: [
        ObjectListItemDirectives,
    ],
    entryComponents: [],
})
export class ObjectListItemModule {
}

registerElement('ObjectListItem', () => ObjectListItem);

在所有这些步骤之后调用模板中的新组件

<!-- [...] -->
<RadListView #myListView [items]="items$ | async">
  <ng-template tkListItemTemplate let-item="item">
    <StackLayout margin="0" padding="0" class="-separator m-y-5" height="90">
      <android>
        <!-- [...] -->
      </android>
      <ios>
          <ObjectListItem [item]="item"></ObjectListItem>
      </ios>
    </StackLayout>
  </ng-template>
</RadListView>
<!-- [...] -->

所有这些工作都花得很好。 UI 更快,感觉更像是一个原生应用程序。 同时,我在 Swift 和 SwiftUI 中构建了一个原生 iOS 应用程序原型,当然这个纯原生应用程序更流畅一点,但目前我使用的是我的原生组件。 希望这个样本对某人有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM