HarmonyOS7 互动卡片和闪控窗,正在重写 UI 交互
前言
上篇我们搞定了 3D 商品展示,今天换个方向——看看 HarmonyOS 7 最吸引眼球的两个 UI 新能力:互动卡片和闪控窗。
这两个东西组合起来能干嘛?简单说就是:你的 App 卡片在桌面上能"动起来",用户摇一摇手机卡片就有动态反馈;同时还能有一个全局悬浮的闪控球,随时呼出智能助手,不用切应用。
互动卡片:不只是静态展示
传统的桌面服务卡片就是一张静态图,点击跳 App。HarmonyOS 7 的互动卡片加了一层"活"的东西——你可以通过传感器事件(比如摇一摇)触发卡片的动态效果。
核心能力
- 静态转动态:摇一摇手机,卡片从静态图变成动画状态
- 前景出框:卡片里的人物/商品可以"溢出"卡片边界,产生立体感
- 视差效果:随手机倾斜角度变化,卡片内元素产生视差移动
互动卡片组件开发
互动卡片还是基于 @Entry 装饰器的 Form 组件,但多了 @Interactive 装饰器和传感器事件绑定:
// card/SmartAssistantCard.ets
@Entry
@Component
@Interactive
struct SmartAssistantCard {
@State isShaking: boolean = false;
@State tiltX: number = 0;
@State tiltY: number = 0;
@StorageLink('cardWeather') weatherData: string = '晴';
build() {
Stack() {
// 背景层——静态天气场景
Image($r('app.media.weather_bg'))
.width('100%')
.height('100%')
.objectFit(ImageFit.Cover)
// 前景元素——会"出框"的天气图标
Image($r('app.media.sun_icon'))
.width(80)
.height(80)
.offset({
x: this.tiltX * 10,
y: this.tiltY * 10 - (this.isShaking ? 20 : 0)
})
.scale({
x: this.isShaking ? 1.2 : 1.0,
y: this.isShaking ? 1.2 : 1.0
})
.animation({
duration: 300,
curve: Curve.EaseOut
})
// 文字信息
Column() {
Text(this.weatherData)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor('#FFFFFF')
Text('智能生活助手')
.fontSize(12)
.fontColor('#CCFFFFFF')
}
.alignItems(HorizontalAlign.Start)
.padding(16)
.layoutAlign(Alignment.BottomStart)
}
.width('100%')
.height('100%')
.borderRadius(16)
// 绑定摇一摇事件
.onShake(() => {
this.isShaking = true;
setTimeout(() => { this.isShaking = false; }, 1500);
})
// 绑定倾斜传感器
.onTilt((event: TiltEvent) => {
this.tiltX = event.angleX;
this.tiltY = event.angleY;
})
}
}

几个要点:@Interactive 装饰器告诉系统这个卡片支持交互事件;onShake 和 onTilt 是卡片专属的传感器回调,普通页面里用不到这套 API。前景出框效果的核心就是让元素在 offset 方向上突破卡片边界——系统会自动裁切掉超出部分,但通过 clip(false) 可以让它"溢出来",产生 3D 感。
卡片配置注册
别忘了在 module.json5 里声明互动能力:
{
"module": {
"extensionAbilities": [{
"name": "SmartAssistantForm",
"type": "form",
"metadata": [{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}],
"interactive": true,
"sensorCapabilities": ["shake", "tilt"]
}]
}
}
interactive: true 和 sensorCapabilities 这两行是关键,少了任何一个,摇一摇和倾斜事件都不会触发。
闪控窗:悬浮窗的终极形态
闪控窗是 HarmonyOS 7 把悬浮窗、侧边栏暂存、闪控球三个东西融为一体的新方案。以前做一个悬浮功能,你得处理窗口管理、边界检测、收纳逻辑,现在系统全帮你搞定。
三种形态
- 悬浮窗模式:正常浮动在屏幕上的小窗口,可以自由拖动和调整大小
- 侧边栏暂存:拖到屏幕边缘自动吸附,变成侧边条,不占空间但随时可拉出来
- 闪控球模式:缩成一个悬浮小球,在任何 App 上方都能显示,点击展开恢复窗口
闪控窗配置
闪控窗通过 window 模块的 StageWindowManager 来管理:
// utils/FlashControlManager.ets
import { window } from '@kit.ArkUI';
export class FlashControlManager {
private flashWindow: window.FlashControlWindow | null = null;
// 创建闪控窗
async create(context: Context): Promise<void> {
const config: window.FlashControlConfig = {
// 初始化为悬浮窗模式
initialMode: window.FlashControlMode.FLOATING,
// 窗口初始尺寸和位置
bounds: {
x: 100,
y: 600,
width: 360,
height: 480
},
// 允许的模式切换
supportedModes: [
window.FlashControlMode.FLOATING,
window.FlashControlMode.SIDEBAR,
window.FlashControlMode.BALL
],
// 闪控球的外观
ballConfig: {
size: 56,
icon: $r('app.media.assistant_ball'),
autoHide: true, // 无操作 5 秒后半透明
edgeAttach: true // 允许吸附屏幕边缘
}
};
this.flashWindow = await window.createFlashControl(context, config);
// 加载卡片内容页面
await this.flashWindow.setUIContent('pages/AssistantFlashPanel');
// 监听模式切换
this.flashWindow.on('modeChanged', (mode: window.FlashControlMode) => {
switch (mode) {
case window.FlashControlMode.BALL:
// 缩成球时,暂停不必要的后台任务
console.info('闪控窗已缩为闪控球');
break;
case window.FlashControlMode.FLOATING:
// 展开时恢复
console.info('闪控窗已展开');
break;
}
});
// 显示
this.flashWindow.show();
}
// 从闪控球状态主动展开
async expand(): Promise<void> {
if (this.flashWindow) {
await this.flashWindow.setMode(window.FlashControlMode.FLOATING);
}
}
// 销毁
destroy(): void {
this.flashWindow?.destroy();
this.flashWindow = null;
}
}

FlashControlConfig 里的 supportedModes 决定了用户能怎么操作。如果不想让用户切成侧边栏,去掉 SIDEBAR 就行。ballConfig.autoHide 挺实用的——闪控球在用户不碰它几秒后自动变半透明,不会挡住底下内容。
闪控窗内的 UI 面板
闪控窗里加载的是一个独立的页面,我们的智能助手面板长这样:
// pages/AssistantFlashPanel.ets
@Entry
@Component
struct AssistantFlashPanel {
@State query: string = '';
@State messages: string[] = [];
build() {
Column() {
// 顶部拖动条(系统自动渲染,但你可以自定义颜色)
Row()
.width(40)
.height(4)
.borderRadius(2)
.backgroundColor('#CCCCCC')
.margin({ top: 8, bottom: 8 })
// 消息列表
List() {
ForEach(this.messages, (msg: string) => {
ListItem() {
Text(msg)
.fontSize(14)
.padding(8)
.backgroundColor('#F0F0F0')
.borderRadius(8)
}
})
}
.layoutWeight(1)
// 输入区
Row() {
TextInput({ placeholder: '问点什么...', text: this.query })
.layoutWeight(1)
.onChange((value: string) => { this.query = value; })
Button('发送')
.onClick(() => {
if (this.query.trim()) {
this.messages.push(this.query);
this.query = '';
}
})
}
.padding(12)
}
.width('100%')
.height('100%')
.backgroundColor('#FFFFFF')
.borderRadius(16)
}
}
把互动卡片和闪控窗串起来
在我们的智能生活助手里,这两个功能是这么配合的:
桌面卡片展示天气/日程摘要 → 用户摇一摇看到动态效果 → 点击卡片"展开详情" → 闪控球弹出悬浮面板 → 用户在面板里跟助手对话。
关键代码是在卡片的点击事件中拉起闪控窗:
// 卡片中点击展开的回调
.onClick(() => {
// 通过 Want 通知主应用启动闪控窗
const want: Want = {
bundleName: 'com.example.smartassistant',
abilityName: 'MainAbility',
action: 'action.showFlashControl'
};
context.startAbility(want);
})
然后在 MainAbility 的 onNewWant 里判断 action,决定是否拉起闪控窗。这部分逻辑比较直白就不展开了。
踩坑与心得
卡片刷新频率有限制。互动卡片的动态更新不是无限的,系统有帧率管控(大约 30fps 上限),别在里面做太复杂的逐帧动画,会卡。
闪控窗权限。创建闪控窗需要 ohos.permission.SYSTEM_FLOAT_WINDOW 权限,这是个 system_grant 权限,需要在 module.json5 里声明。普通应用能申请到,但审核时华为会看你的使用场景是否合理。
侧边栏暂存的 UI 适配。从悬浮窗拖到侧边栏时,窗口宽度会被压到很窄。你的 UI 得能响应这个变化,建议用 MediaQuery 做适配,或者监听 boundsChanged 事件动态调整布局。
小结
互动卡片和闪控窗是 HarmonyOS 7 在系统级 UI 上的大升级。互动卡片让桌面不再只是图标排列,闪控窗让悬浮交互有了标准化方案。做智能助手这类需要"常驻"和"随时可达"的应用,这两个能力几乎是必选项。
下一篇我们聊多形态服务窗口——悬浮窗、分屏、平行视界,看看怎么让 App 在不同设备形态上都好用。
更多推荐


所有评论(0)