相信很多小伙伴都觉得鸿蒙原生的模态窗很好看,但困惑的是其需要绑定组件:
Button('Open Sheet').width('90%').height('80vp')
.onClick(() => {
this.isShowSheet = !this.isShowSheet;
})
.bindSheet($$this.isShowSheet, this.SheetBuilder(), {
detents: [SheetSize.MEDIUM, SheetSize.LARGE, 600],
preferType: SheetType.BOTTOM,
// 请将$r('app.string.tSheetBuilder_text2')替换为实际资源文件,在本示例中该资源文件的value值为"嵌套滚动场景"
title: { title: $r('app.string.tSheetBuilder_text2') },
})
那是否意味着Flutter开发的程序无法调用?
不
可以找到Flutter的鸿蒙工程中的Index.ets, 在原来的column背后加上.bindSheet即可。
Column() {
FlutterPage({ viewId: this.viewId })
}.bindSheet($$this.isShowSheet, this.SheetBuilder(), {
detents: [SheetSize.LARGE],
preferType: SheetType.BOTTOM,
onDisappear: () => {
AppStorage.setOrCreate<boolean>('isShowSheet', false);
}
})
也是在这个文件里,在Index这个struct中加上
@StorageLink('isShowSheet') isShowSheet: boolean = false;
private webController: webview.WebviewController = new webview.WebviewController();
@Builder
SheetBuilder() {
Column() {
Web({ src: 'https://baidu.com', controller: this.webController })
.width('100%')
.height('100%')
.nestedScroll({
scrollForward: NestedScrollMode.PARENT_FIRST,
scrollBackward: NestedScrollMode.SELF_FIRST,
})
}
.width('100%')
.height('100%')
}
这个builder即可控制控制显示的内容,这里我们显示了一个网页。
到这里,我们的Flutter鸿蒙混合App是可以调用原生的模态窗口了,但需要有调用的地方。于是需要写一个插件:
// entry/src/main/ets/plugin/SheetPlugin.ets
import {
FlutterPlugin,
FlutterPluginBinding,
MethodChannel,
MethodCallHandler,
MethodCall,
MethodResult,
AbilityPluginBinding,
} from '@ohos/flutter_ohos';
import UIAbility from '@ohos.app.ability.UIAbility';
export class SheetPlugin implements FlutterPlugin, MethodCallHandler {
private channel: MethodChannel | null = null;
private ability: UIAbility;
constructor(ability: UIAbility) {
this.ability = ability;
}
getUniqueClassName(): string {
return 'SheetPlugin';
}
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel = new MethodChannel(
binding.getBinaryMessenger(),
'com.xxx/sheet' // 与 Flutter 侧一致
);
this.channel.setMethodCallHandler(this);
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
this.channel?.setMethodCallHandler(null);
this.channel = null;
}
onMethodCall(call: MethodCall, result: MethodResult): void {
if (call.method === 'openSheet') {
this.triggerSheet();
result.success(null);
} else {
result.notImplemented();
}
}
private triggerSheet(): void {
// 通过 AppStorage 驱动状态变更
AppStorage.setOrCreate<boolean>('isShowSheet', true);
}
}
然后在EntryAbility注册插件:
flutterEngine.getPlugins()?.add(new SheetPlugin(this));
最后在Flutter端写调用的代码:
static Future<void> openSheet() async {
const String channelPath =
"com.xxx/sheet"; //这儿要与MethodChannel(flutterEngine?.dartExecutor, CHANNEL)中CHANNEL名称一致
const MethodChannel channel = const MethodChannel(channelPath);
try {
await channel.invokeMethod('openSheet');
} on PlatformException catch (e) {
print('调用 Sheet 失败: ${e.message}');
}
}
然后在UI中调用:
GestureDetector(
onTap: () {
LaunchUtils.openSheet();
},
child: UniversalWidget(context)),
大工告成,假如你也是Flutter+ArkTS混合开发,也来试试吧!