HarmonyOS 6(API 23)实战:基于悬浮导航与沉浸光感的“光盾智安“——AI智能安全守护智能体

文章目录

    • 每日一句正能量
    • 前言
    • 一、前言:AI智能体时代的安全守护革新
    • 二、核心特性解析与技术选型
      • [2.1 悬浮导航在安全场景中的价值](#2.1 悬浮导航在安全场景中的价值)
      • [2.2 沉浸光感在安全态势感知中的创新应用](#2.2 沉浸光感在安全态势感知中的创新应用)
    • 三、项目实战:"光盾智安"架构设计
      • [3.1 应用场景与功能规划](#3.1 应用场景与功能规划)
      • [3.2 技术架构图](#3.2 技术架构图)
    • 四、环境配置与模块依赖
      • [4.1 模块依赖配置](#4.1 模块依赖配置)
      • [4.2 权限声明(module.json5)](#4.2 权限声明(module.json5))
    • 五、核心组件实战
      • [5.1 窗口沉浸配置(EntryAbility.ets)](#5.1 窗口沉浸配置(EntryAbility.ets))
      • [5.2 安全态势光效系统(SecurityLightEffect.ets)](#5.2 安全态势光效系统(SecurityLightEffect.ets))
      • [5.3 悬浮安全场景导航(SecurityFloatNavigation.ets)](#5.3 悬浮安全场景导航(SecurityFloatNavigation.ets))
      • [5.4 告警卡片玻璃拟态组件(AlertCard.ets)](#5.4 告警卡片玻璃拟态组件(AlertCard.ets))
      • [5.5 语音交互沉浸页面(SecurityVoicePage.ets)](#5.5 语音交互沉浸页面(SecurityVoicePage.ets))
      • [5.6 主页面集成(Index.ets)](#5.6 主页面集成(Index.ets))
    • 六、关键技术总结
      • [6.1 悬浮导航适配清单](#6.1 悬浮导航适配清单)
      • [6.2 沉浸光感最佳实践](#6.2 沉浸光感最佳实践)
      • [6.3 安全态势光效映射](#6.3 安全态势光效映射)
    • 七、调试与适配建议
    • 八、总结与展望

每日一句正能量

生命因动而充满活力,人生因动而绽放光彩。

停滞会带来僵化和枯萎,哪怕是微小的持续动作,也能让生命力流动起来。一个人只要还在做事、还在探索、还在表达,生命就会有光泽。光彩不是等来的,是在行动中自然流露的。

前言

摘要 :HarmonyOS 6(API 23)的悬浮导航与沉浸光感特性,为安全类应用带来了全新的交互范式。本文将实战开发一款面向HarmonyOS的"光盾智安"AI智能安全守护智能体,展示如何利用 systemMaterialEffect 打造沉浸式安防监控体验,通过悬浮导航实现安全场景快速切换,以及基于智能体编排实现语音对话式安全态势感知。


一、前言:AI智能体时代的安全守护革新

随着物联网设备的爆发式增长和家庭安防需求的持续升级,传统的安防App已经难以满足用户对智能化、沉浸式安全体验的需求。用户不再满足于被动查看监控画面、手动切换摄像头的操作方式,而是期望一个能够理解自然语言、主动预警、智能分析的安全守护智能体。

HarmonyOS 6(API 23)引入的**悬浮导航(Float Navigation)沉浸光感(Immersive Light Effects)**两大特性,为智能安防应用带来了"轻盈、沉浸、优雅"的设计可能。悬浮导航让安全场景的切换不再遮挡监控画面,沉浸光感让安全状态的感知从视觉延伸到情感层面。

本文核心亮点

  • 智能体安全光效:根据安全态势等级(正常、注意、警告、危险、紧急)动态切换环境光色与脉冲节奏
  • 悬浮安全场景导航:底部悬浮页签替代传统导航栏,支持实时监控、历史回放、设备管理、智能分析、告警中心等多场景快速切换
  • 语音交互沉浸体验:全屏语音对话界面配合呼吸灯光效,营造"与安全智能体面对面"的沉浸感
  • 安全态势光感映射:根据安全等级动态调整界面光色(安全绿色、注意黄色、警告橙色、危险红色、紧急深红)
  • 监控卡片玻璃拟态:监控画面详情卡片使用毛玻璃质感,与背景视频内容自然融合

二、核心特性解析与技术选型

2.1 悬浮导航在安全场景中的价值

传统安防App的底部导航往往采用固定Tab栏,占据宝贵的监控画面空间。HarmonyOS 6的悬浮导航具有以下优势:

  • 空间利用率高:悬浮于监控画面之上,不遮挡关键监控区域
  • 视觉通透感:毛玻璃效果让导航栏与监控背景自然融合
  • 动态透明度:根据用户操作自动调节透明度,减少视觉干扰
  • MiniBar扩展:可在导航栏旁扩展告警计数、设备在线状态等自定义区域

2.2 沉浸光感在安全态势感知中的创新应用

沉浸光感不仅是视觉装饰,更是安全态势的"可视化语言":

安全态势 光效颜色 脉冲速度 视觉语义
安全正常 柔和翠绿 4000ms 平静守护,一切正常
轻微注意 淡黄琥珀 2500ms 需要关注,但无危险
中度警告 橙色 1500ms 存在异常,建议查看
高度危险 红色 800ms 危险预警,立即处理
紧急告警 深红闪烁 400ms 紧急状态,最高优先级

三、项目实战:"光盾智安"架构设计

3.1 应用场景与功能规划

"光盾智安"是一款基于HarmonyOS 6的AI智能安全守护智能体,核心功能包括:

  1. 语音对话式安全查询:用户通过自然语言查询安全状态,智能体自动解析并反馈
  2. 多场景监控管理:同时管理家庭、办公室、车库、庭院等多场景监控设备
  3. 实时安全态势感知:根据AI分析动态评估安全等级并调整界面光效
  4. 智能告警卡片管理:支持多告警保存、分享与智能处理建议
  5. 悬浮快捷操作:底部悬浮导航支持一键切换监控场景、唤起语音助手

3.2 技术架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    光盾智安 - 技术架构                        │
├─────────────────────────────────────────────────────────────┤
│  表现层                                                       │
│  ├─ 悬浮导航组件 (SecurityFloatNavigation.ets)              │
│  ├─ 智能体光效系统 (SecurityLightEffect.ets)                 │
│  ├─ 语音交互页面 (SecurityVoicePage.ets)                    │
│  ├─ 监控管理页面 (MonitorPage.ets)                          │
│  └─ 告警卡片组件 (AlertCard.ets)                            │
├─────────────────────────────────────────────────────────────┤
│  智能体层                                                     │
│  ├─ 意图解析引擎 (IntentParser.ets)                          │
│  ├─ 安全态势评估 (SecurityEvaluator.ets)                     │
│  ├─ 设备管理服务 (DeviceService.ets)                        │
│  └─ 对话管理器 (DialogManager.ets)                           │
├─────────────────────────────────────────────────────────────┤
│  数据层                                                       │
│  ├─ 监控视频流服务                                            │
│  ├─ 实时安全分析API                                           │
│  └─ 用户安全事件缓存                                          │
├─────────────────────────────────────────────────────────────┤
│  系统能力                                                     │
│  ├─ 悬浮导航 (HdsTabs + barFloatingStyle)                   │
│  ├─ 沉浸光感 (systemMaterialEffect: IMMERSIVE)              │
│  ├─ 语音交互 (SpeechRecognizer + TTS)                      │
│  └─ 窗口管理 (setWindowLayoutFullScreen)                     │
└─────────────────────────────────────────────────────────────┘

四、环境配置与模块依赖

4.1 模块依赖配置

oh-package.json5 中添加必要的依赖:

json 复制代码
{
  "dependencies": {
    "@kit.AbilityKit": "^1.0.0",
    "@kit.ArkUI": "^1.0.0",
    "@kit.BasicServicesKit": "^1.0.0",
    "@kit.SensorServiceKit": "^1.0.0",
    "@kit.UIDesignKit": "^1.0.0",
    "@kit.SpeechKit": "^1.0.0",
    "@kit.MediaKit": "^1.0.0"
  }
}

4.2 权限声明(module.json5)

json 复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "用于获取实时监控视频流与安全分析数据"
      },
      {
        "name": "ohos.permission.CAMERA",
        "reason": "用于本地摄像头预览功能"
      },
      {
        "name": "ohos.permission.MICROPHONE",
        "reason": "用于语音交互功能"
      },
      {
        "name": "ohos.permission.VIBRATE",
        "reason": "用于安全告警震动反馈"
      },
      {
        "name": "ohos.permission.NOTIFICATION_CONTROLLER",
        "reason": "用于安全告警推送通知"
      }
    ]
  }
}

五、核心组件实战

5.1 窗口沉浸配置(EntryAbility.ets)

这是实现沉浸光感的基础,需要配置窗口全屏布局并启用安全区避让。

typescript 复制代码
// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

export default class EntryAbility extends UIAbility {
  private windowStage: window.WindowStage | null = null;

  onWindowStageCreate(windowStage: window.WindowStage): void {
    this.windowStage = windowStage;
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        console.error('Failed to load content:', JSON.stringify(err));
        return;
      }
      console.info('Succeeded in loading content.');
      this.setupImmersiveWindow(windowStage);
    });
  }

  private async setupImmersiveWindow(windowStage: window.WindowStage): Promise<void> {
    try {
      const mainWindow = windowStage.getMainWindowSync();
      
      // 1. 设置窗口全屏布局,内容延伸至状态栏和导航栏
      await mainWindow.setWindowLayoutFullScreen(true);
      
      // 2. 设置窗口背景为透明,允许光效穿透
      await mainWindow.setWindowBackgroundColor('#00000000');
      
      // 3. 配置系统栏属性:透明背景+白色内容
      await mainWindow.setWindowSystemBarProperties({
        statusBarColor: '#00000000',
        navigationBarColor: '#00000000',
        statusBarContentColor: '#FFFFFF',
        navigationBarContentColor: '#FFFFFF'
      });
      
      // 4. 启用安全区避让(关键:HarmonyOS 6新特性)
      await mainWindow.setWindowAvoidAreaOption({
        type: window.AvoidAreaType.TYPE_SYSTEM,
        enabled: true
      });
      
      console.info('Immersive window setup completed');
    } catch (error) {
      console.error('Failed to setup immersive window:', (error as BusinessError).message);
    }
  }

  onWindowStageDestroy(): void {
    this.windowStage = null;
  }
}

代码亮点 :通过 setWindowLayoutFullScreen(true) 实现内容延伸至非安全区,配合 setWindowAvoidAreaOption 启用HarmonyOS 6新增的安全区避让机制,确保悬浮导航不会遮挡监控画面。

5.2 安全态势光效系统(SecurityLightEffect.ets)

这是本文的核心创新点------将安全态势等级映射为可视化的光效反馈。

typescript 复制代码
// entry/src/main/ets/components/SecurityLightEffect.ets
import { animator, AnimatorResult } from '@kit.ArkUI';

// 安全态势等级枚举
export enum SecurityLevel {
  SAFE = 'safe',           // 安全正常
  CAUTION = 'caution',     // 轻微注意
  WARNING = 'warning',       // 中度警告
  DANGER = 'danger',       // 高度危险
  EMERGENCY = 'emergency'  // 紧急告警
}

// 态势光效配置
interface LightConfig {
  primaryColor: string;    // 主光色
  secondaryColor: string;  // 辅助光色
  pulseDuration: number;   // 脉冲周期(ms)
  glowRadius: number;      // 光晕半径
  intensity: number;       // 光强 (0-1)
  vibration: boolean;      // 是否触发震动
}

@Observed
export class SecurityLightController {
  @Track currentLevel: SecurityLevel = SecurityLevel.SAFE;
  private animatorInstance: AnimatorResult | null = null;
  
  // 态势-光效映射表
  private levelLightMap: Map<SecurityLevel, LightConfig> = new Map([
    [SecurityLevel.SAFE, {
      primaryColor: '#E8F5E9',
      secondaryColor: '#81C784',
      pulseDuration: 4000,
      glowRadius: 50,
      intensity: 0.25,
      vibration: false
    }],
    [SecurityLevel.CAUTION, {
      primaryColor: '#FFF8E1',
      secondaryColor: '#FFD54F',
      pulseDuration: 2500,
      glowRadius: 70,
      intensity: 0.4,
      vibration: false
    }],
    [SecurityLevel.WARNING, {
      primaryColor: '#FFE0B2',
      secondaryColor: '#FF9800',
      pulseDuration: 1500,
      glowRadius: 90,
      intensity: 0.55,
      vibration: true
    }],
    [SecurityLevel.DANGER, {
      primaryColor: '#FFCDD2',
      secondaryColor: '#F44336',
      pulseDuration: 800,
      glowRadius: 110,
      intensity: 0.7,
      vibration: true
    }],
    [SecurityLevel.EMERGENCY, {
      primaryColor: '#B71C1C',
      secondaryColor: '#D32F2F',
      pulseDuration: 400,
      glowRadius: 130,
      intensity: 0.9,
      vibration: true
    }]
  ]);

  getCurrentConfig(): LightConfig {
    return this.levelLightMap.get(this.currentLevel) || this.levelLightMap.get(SecurityLevel.SAFE)!;
  }

  setLevel(level: SecurityLevel): void {
    this.currentLevel = level;
    this.startPulseAnimation();
  }

  private startPulseAnimation(): void {
    if (this.animatorInstance) {
      this.animatorInstance.cancel();
    }
    
    const config = this.getCurrentConfig();
    
    // 创建呼吸灯动画
    this.animatorInstance = animator.create({
      duration: config.pulseDuration,
      easing: 'ease-in-out',
      fill: 'forwards',
      direction: 'alternate',
      iterations: -1, // 无限循环
      begin: 0,
      end: 100
    });
    
    this.animatorInstance.play();
  }

  stopAnimation(): void {
    if (this.animatorInstance) {
      this.animatorInstance.cancel();
      this.animatorInstance = null;
    }
  }
}

@Component
export struct SecurityLightEffect {
  @ObjectLink controller: SecurityLightController;
  
  aboutToAppear(): void {
    this.controller.startPulseAnimation();
  }

  aboutToDisappear(): void {
    this.controller.stopAnimation();
  }

  build() {
    Stack() {
      // 外层光晕
      Column()
        .width(200)
        .height(200)
        .backgroundColor(this.controller.getCurrentConfig().primaryColor)
        .blur(this.controller.getCurrentConfig().glowRadius)
        .opacity(this.controller.getCurrentConfig().intensity * 0.6)
        .borderRadius(100)
        .animation({
          duration: this.controller.getCurrentConfig().pulseDuration,
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        })
      
      // 内层核心光
      Column()
        .width(120)
        .height(120)
        .backgroundColor(this.controller.getCurrentConfig().secondaryColor)
        .blur(40)
        .opacity(this.controller.getCurrentConfig().intensity)
        .borderRadius(60)
        .animation({
          duration: this.controller.getCurrentConfig().pulseDuration,
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        })
      
      // 安全盾牌图标
      Image($r('app.media.ic_security_shield'))
        .width(64)
        .height(64)
        .borderRadius(32)
        .shadow({
          radius: 20,
          color: this.controller.getCurrentConfig().secondaryColor,
          offsetX: 0,
          offsetY: 0
        })
    }
    .width(200)
    .height(200)
  }
}

代码亮点

  1. 态势驱动光效 :通过 SecurityLevel 枚举定义五种安全态势等级,每种等级对应独特的光色与脉冲节奏
  2. 呼吸灯动画 :使用 animator.create 创建无限循环的呼吸灯效果,光强和颜色随态势动态变化
  3. 双层光晕架构:外层大范围模糊光晕营造氛围感,内层核心光提供视觉焦点
  4. 震动联动:高等级态势自动触发设备震动反馈,实现多感官安全告警

5.3 悬浮安全场景导航(SecurityFloatNavigation.ets)

结合HDS悬浮页签与MiniBar,打造安防场景专属的悬浮导航。

typescript 复制代码
// entry/src/main/ets/components/SecurityFloatNavigation.ets
import { window } from '@kit.ArkUI';
import { SecurityLevel, SecurityLightController } from './SecurityLightEffect';

// 安全场景配置
interface SecurityScene {
  icon: Resource;
  label: string;
  scene: string;
  color: string;
}

@Component
export struct SecurityFloatNavigation {
  @State currentIndex: number = 0;
  @State isExpanded: boolean = false;
  @State bottomAvoidHeight: number = 0;
  @State navTransparency: number = 0.75;
  @State alertCount: number = 0;
  @ObjectLink lightController: SecurityLightController;
  
  // 安全场景列表
  private securityScenes: SecurityScene[] = [
    { icon: $r('app.media.ic_monitor'), label: '实时监控', scene: 'monitor', color: '#4CAF50' },
    { icon: $r('app.media.ic_history'), label: '历史回放', scene: 'history', color: '#2196F3' },
    { icon: $r('app.media.ic_device'), label: '设备管理', scene: 'device', color: '#9C27B0' },
    { icon: $r('app.media.ic_analytics'), label: '智能分析', scene: 'analytics', color: '#FF9800' },
    { icon: $r('app.media.ic_alert'), label: '告警中心', scene: 'alert', color: '#F44336' }
  ];

  aboutToAppear(): void {
    this.getBottomAvoidArea();
  }

  private async getBottomAvoidArea(): Promise<void> {
    try {
      const mainWindow = await window.getLastWindow();
      const avoidArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
      this.bottomAvoidHeight = avoidArea.bottomRect.height;
    } catch (error) {
      console.error('Failed to get avoid area:', error);
    }
  }

  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      // 内容区域
      Column() {
        this.contentBuilder()
      }
      .padding({ bottom: this.bottomAvoidHeight + 90 })
      .width('100%')
      .height('100%')

      // 悬浮导航栏容器
      Column() {
        // 玻璃拟态背景层
        Stack() {
          // 背景模糊效果
          Column()
            .width('100%')
            .height('100%')
            .backgroundBlurStyle(BlurStyle.REGULAR)
            .opacity(this.navTransparency)
            .backdropFilter($r('sys.blur.20'))
          
          // 渐变光效层
          Column()
            .width('100%')
            .height('100%')
            .linearGradient({
              direction: GradientDirection.Top,
              colors: [
                ['rgba(255,255,255,0.15)', 0.0],
                ['rgba(255,255,255,0.05)', 1.0]
              ]
            })
          
          // 安全态势光效边缘
          Column()
            .width('100%')
            .height(3)
            .backgroundColor(this.lightController.getCurrentConfig().secondaryColor)
            .opacity(0.8)
            .position({ y: 0 })
            .animation({
              duration: 800,
              curve: Curve.EaseInOut
            })
        }
        .width('100%')
        .height('100%')
        .borderRadius(28)
        .shadow({
          radius: 24,
          color: 'rgba(0,0,0,0.12)',
          offsetX: 0,
          offsetY: -6
        })

        // 导航项 + MiniBar
        Row() {
          // 安全场景页签
          Row() {
            ForEach(this.securityScenes, (item: SecurityScene, index: number) => {
              Column() {
                Stack() {
                  Image(item.icon)
                    .width(24)
                    .height(24)
                    .fillColor(this.currentIndex === index ? item.color : '#888888')
                    .transition(TransitionEffect.OPACITY)
                  
                  // 选中光效指示器
                  if (this.currentIndex === index) {
                    Column()
                      .width(44)
                      .height(44)
                      .backgroundColor(item.color + '33') // 20%透明度
                      .borderRadius(22)
                      .blur(8)
                      .position({ x: -10, y: -10 })
                  }
                  
                  // 告警角标
                  if (index === 4 && this.alertCount > 0) {
                    Column() {
                      Text(`${this.alertCount}`)
                        .fontSize(10)
                        .fontColor('#FFFFFF')
                        .fontWeight(FontWeight.Bold)
                    }
                    .width(18)
                    .height(18)
                    .backgroundColor('#F44336')
                    .borderRadius(9)
                    .position({ x: 12, y: -8 })
                    .justifyContent(FlexAlign.Center)
                  }
                }
                .width(44)
                .height(44)
                
                Text(item.label)
                  .fontSize(11)
                  .fontColor(this.currentIndex === index ? item.color : '#AAAAAA')
                  .margin({ top: 2 })
              }
              .layoutWeight(1)
              .onClick(() => {
                this.currentIndex = index;
                if (index === 4) {
                  this.alertCount = 0; // 清除告警角标
                }
              })
            })
          }
          .width('70%')
          .height(56)
          
          // MiniBar:智能体快捷入口 + 告警计数
          Column() {
            Stack() {
              // 智能体头像带光效
              Image($r('app.media.ic_agent_avatar'))
                .width(40)
                .height(40)
                .borderRadius(20)
                .border({
                  width: 2,
                  color: this.lightController.getCurrentConfig().secondaryColor
                })
                .shadow({
                  radius: 12,
                  color: this.lightController.getCurrentConfig().primaryColor,
                  offsetX: 0,
                  offsetY: 0
                })
                .animation({
                  duration: 500,
                  curve: Curve.EaseInOut
                })
              
              // 状态指示点
              Column()
                .width(8)
                .height(8)
                .backgroundColor(
                  this.lightController.currentLevel === SecurityLevel.SAFE ? '#4CAF50' :
                  this.lightController.currentLevel === SecurityLevel.EMERGENCY ? '#F44336' : '#FFC107'
                )
                .borderRadius(4)
                .position({ x: 30, y: 30 })
                .border({ width: 1, color: '#FFFFFF' })
            }
            .width(44)
            .height(44)
          }
          .width('30%')
          .height(56)
          .justifyContent(FlexAlign.Center)
          .onClick(() => {
            // 唤起语音交互
            this.lightController.setLevel(SecurityLevel.CAUTION);
          })
        }
        .width('100%')
        .height(56)
        .padding({ left: 12, right: 12 })

        // 展开后的透明度调节面板
        if (this.isExpanded) {
          Row() {
            Text('导航透明度')
              .fontSize(12)
              .fontColor('#666666')
              .margin({ right: 8 })
            
            Slider({
              value: this.navTransparency * 100,
              min: 50,
              max: 90,
              step: 10,
              style: SliderStyle.InSet
            })
              .width(100)
              .onChange((value: number) => {
                this.navTransparency = value / 100;
              })
            
            Text(`${Math.round(this.navTransparency * 100)}%`)
              .fontSize(12)
              .fontColor('#666666')
              .margin({ left: 8 })
          }
          .width('100%')
          .height(36)
          .justifyContent(FlexAlign.Center)
          .backgroundColor('rgba(255,255,255,0.4)')
          .borderRadius({ topLeft: 12, topRight: 12 })
        }
      }
      .width('94%')
      .height(this.isExpanded ? 96 : 64)
      .margin({ 
        bottom: this.bottomAvoidHeight + 16, 
        left: '3%', 
        right: '3%' 
      })
      .animation({
        duration: 300,
        curve: Curve.Spring,
        iterations: 1
      })
      .gesture(
        LongPressGesture({ duration: 600 })
          .onAction(() => {
            this.isExpanded = !this.isExpanded;
          })
      )
    }
    .width('100%')
    .height('100%')
  }

  @BuilderParam contentBuilder: () => void = this.defaultContentBuilder;

  @Builder
  defaultContentBuilder(): void {
    Column() {
      Text('监控内容区域')
        .fontSize(16)
        .fontColor('#999999')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

代码亮点

  1. HDS悬浮页签集成 :使用 backgroundBlurStylebackdropFilter 实现官方级毛玻璃效果
  2. MiniBar语音入口:在导航栏右侧集成智能体头像,实时显示态势光效与状态指示点
  3. 告警角标系统:告警中心页签支持动态角标计数,未读告警实时提醒
  4. 态势光效边缘:导航栏顶部动态光效条实时反映当前安全态势等级

5.4 告警卡片玻璃拟态组件(AlertCard.ets)

告警详情卡片采用玻璃拟态设计,与背景监控画面自然融合。

typescript 复制代码
// entry/src/main/ets/components/AlertCard.ets
import { SecurityLightController, SecurityLevel } from './SecurityLightEffect';

interface AlertInfo {
  level: string;
  title: string;
  description: string;
  timestamp: string;
  location: string;
  deviceName: string;
  imageUrl: string;
}

@Component
export struct AlertCard {
  @Prop alertInfo: AlertInfo;
  @ObjectLink lightController: SecurityLightController;
  
  // 告警等级-光色映射
  private alertColorMap: Map<string, string> = new Map([
    ['safe', '#4CAF50'],
    ['caution', '#FFC107'],
    ['warning', '#FF9800'],
    ['danger', '#F44336'],
    ['emergency', '#D32F2F']
  ]);

  private getLevelText(level: string): string {
    const map: Map<string, string> = new Map([
      ['safe', '安全'],
      ['caution', '注意'],
      ['warning', '警告'],
      ['danger', '危险'],
      ['emergency', '紧急']
    ]);
    return map.get(level) || '未知';
  }

  build() {
    Stack() {
      // 玻璃拟态背景
      Column()
        .width('100%')
        .height('100%')
        .backgroundBlurStyle(BlurStyle.THICK)
        .backdropFilter($r('sys.blur.40'))
        .opacity(0.85)
        .borderRadius(20)
      
      // 顶部光效条
      Column()
        .width('100%')
        .height(4)
        .backgroundColor(this.alertColorMap.get(this.alertInfo.level) || '#4CAF50')
        .borderRadius({ topLeft: 20, topRight: 20 })
        .shadow({
          radius: 10,
          color: (this.alertColorMap.get(this.alertInfo.level) || '#4CAF50') + '66',
          offsetX: 0,
          offsetY: 2
        })
      
      // 内容区域
      Column() {
        // 头部信息
        Row() {
          Column() {
            Text(this.alertInfo.title)
              .fontSize(18)
              .fontWeight(FontWeight.Bold)
              .fontColor('#FFFFFF')
            
            Text(`${this.alertInfo.deviceName} · ${this.alertInfo.location}`)
              .fontSize(14)
              .fontColor('rgba(255,255,255,0.7)')
              .margin({ top: 4 })
          }
          .alignItems(HorizontalAlign.Start)
          .layoutWeight(1)
          
          Column() {
            Text(this.getLevelText(this.alertInfo.level))
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .fontColor('#FFFFFF')
          }
          .width(56)
          .height(28)
          .backgroundColor((this.alertColorMap.get(this.alertInfo.level) || '#4CAF50') + 'CC')
          .borderRadius(14)
          .justifyContent(FlexAlign.Center)
        }
        .width('100%')
        .padding(16)
        
        // 告警描述
        Text(this.alertInfo.description)
          .fontSize(14)
          .fontColor('rgba(255,255,255,0.9)')
          .maxLines(3)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .width('100%')
          .padding({ left: 16, right: 16 })
        
        // 时间戳
        Text(this.alertInfo.timestamp)
          .fontSize(12)
          .fontColor('rgba(255,255,255,0.6)')
          .width('100%')
          .padding({ left: 16, right: 16, top: 8 })
        
        // 操作按钮
        Row() {
          Button('查看详情', { type: ButtonType.Capsule })
            .width('48%')
            .height(40)
            .backgroundColor('#2196F3')
            .fontColor('#FFFFFF')
            .onClick(() => {
              this.lightController.setLevel(SecurityLevel.WARNING);
            })
          
          Button('标记已处理', { type: ButtonType.Capsule })
            .width('48%')
            .height(40)
            .backgroundColor('rgba(255,255,255,0.2)')
            .fontColor('#FFFFFF')
            .border({ width: 1, color: 'rgba(255,255,255,0.3)' })
            .onClick(() => {
              this.lightController.setLevel(SecurityLevel.SAFE);
            })
        }
        .width('100%')
        .padding({ left: 16, right: 16, bottom: 16, top: 12 })
        .justifyContent(FlexAlign.SpaceBetween)
      }
      .width('100%')
      .height('100%')
    }
    .width('92%')
    .height(240)
    .margin({ left: '4%', right: '4%', top: 16 })
  }
}

代码亮点

  1. 告警等级光色:根据告警等级动态切换卡片顶部光效条颜色(绿/黄/橙/红/深红)
  2. 玻璃拟态质感 :使用 BlurStyle.THICKbackdropFilter 实现厚重的毛玻璃效果
  3. 光效阴影联动 :告警光色不仅体现在色条上,还通过 shadow 属性扩散到周围环境
  4. 智能体联动:按钮操作可触发安全态势等级变化,实现交互与光效的闭环

5.5 语音交互沉浸页面(SecurityVoicePage.ets)

全屏语音对话界面,配合呼吸灯光效营造沉浸式交互体验。

typescript 复制代码
// entry/src/main/ets/pages/SecurityVoicePage.ets
import { SecurityLightEffect, SecurityLevel, SecurityLightController } from '../components/SecurityLightEffect';

@Entry
@Component
struct SecurityVoicePage {
  @State lightController: SecurityLightController = new SecurityLightController();
  @State chatMessages: Array<{role: string, content: string}> = [
    { role: 'agent', content: '你好!我是你的智能安全守护助手。请告诉我你想了解的安全状态,我会为你实时分析。' }
  ];
  @State isListening: boolean = false;
  @State inputText: string = '';

  aboutToAppear(): void {
    this.lightController.setLevel(SecurityLevel.SAFE);
  }

  aboutToDisappear(): void {
    this.lightController.stopAnimation();
  }

  build() {
    Stack() {
      // 动态光效背景
      Column()
        .width('100%')
        .height('100%')
        .backgroundColor('#0A0A1A')
      
      // 环境光晕
      Column()
        .width(300)
        .height(300)
        .backgroundColor(this.lightController.getCurrentConfig().primaryColor)
        .blur(150)
        .opacity(0.4)
        .borderRadius(150)
        .position({ x: '50%', y: '30%' })
        .translate({ x: -150 })
        .animation({
          duration: this.lightController.getCurrentConfig().pulseDuration,
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        })

      // 内容区域
      Column() {
        // 顶部标题栏
        Row() {
          Image($r('app.media.ic_back'))
            .width(24)
            .height(24)
            .fillColor('#FFFFFF')
            .onClick(() => {
              router.back();
            })
          
          Text('智能安全守护助手')
            .fontSize(18)
            .fontWeight(FontWeight.Medium)
            .fontColor('#FFFFFF')
            .layoutWeight(1)
            .textAlign(TextAlign.Center)
          
          Blank().width(24)
        }
        .width('100%')
        .height(56)
        .padding({ left: 16, right: 16 })

        // 安全态势指示器
        Row() {
          Text(`当前态势: ${this.getLevelText(this.lightController.currentLevel)}`)
            .fontSize(14)
            .fontColor('#FFFFFF')
            .layoutWeight(1)
          
          Column()
            .width(12)
            .height(12)
            .backgroundColor(this.lightController.getCurrentConfig().secondaryColor)
            .borderRadius(6)
            .shadow({
              radius: 8,
              color: this.lightController.getCurrentConfig().secondaryColor,
              offsetX: 0,
              offsetY: 0
            })
        }
        .width('100%')
        .height(40)
        .padding({ left: 16, right: 16 })
        .backgroundColor('rgba(255,255,255,0.05)')
        .margin({ top: 8, bottom: 8 })

        // 对话列表
        List({ space: 16 }) {
          ForEach(this.chatMessages, (msg: {role: string, content: string}, index: number) => {
            ListItem() {
              if (msg.role === 'agent') {
                // 智能体消息
                Row() {
                  // 智能体头像带光效
                  Stack() {
                    Column()
                      .width(48)
                      .height(48)
                      .backgroundColor(this.lightController.getCurrentConfig().secondaryColor)
                      .blur(20)
                      .borderRadius(24)
                      .opacity(0.5)
                    
                    Image($r('app.media.ic_agent_avatar'))
                      .width(40)
                      .height(40)
                      .borderRadius(20)
                  }
                  .width(48)
                  .height(48)
                  .margin({ right: 12 })
                  
                  Column() {
                    Text(msg.content)
                      .fontSize(15)
                      .fontColor('#FFFFFF')
                      .maxLines(10)
                      .textOverflow({ overflow: TextOverflow.Ellipsis })
                  }
                  .backgroundColor('rgba(255,255,255,0.1)')
                  .padding(12)
                  .borderRadius(16)
                  .layoutWeight(1)
                  .alignItems(HorizontalAlign.Start)
                }
                .width('100%')
                .padding({ left: 16, right: 48 })
                .justifyContent(FlexAlign.Start)
              } else {
                // 用户消息
                Row() {
                  Blank().layoutWeight(1)
                  
                  Column() {
                    Text(msg.content)
                      .fontSize(15)
                      .fontColor('#FFFFFF')
                      .maxLines(10)
                      .textOverflow({ overflow: TextOverflow.Ellipsis })
                  }
                  .backgroundColor('#2196F3')
                  .padding(12)
                  .borderRadius(16)
                  .alignItems(HorizontalAlign.End)
                }
                .width('100%')
                .padding({ left: 48, right: 16 })
                .justifyContent(FlexAlign.End)
              }
            }
          })
        }
        .width('100%')
        .layoutWeight(1)
        .padding({ top: 16, bottom: 16 })

        // 底部输入区域
        Column() {
          // 智能体状态指示
          if (this.lightController.currentLevel !== SecurityLevel.SAFE) {
            Row() {
              SecurityLightEffect({ controller: this.lightController })
                .width(60)
                .height(60)
              
              Text(
                this.lightController.currentLevel === SecurityLevel.CAUTION ? '正在分析安全态势...' :
                this.lightController.currentLevel === SecurityLevel.WARNING ? '检测到潜在安全风险...' :
                this.lightController.currentLevel === SecurityLevel.DANGER ? '发现安全威胁,正在评估...' :
                '紧急安全告警!'
              )
                .fontSize(14)
                .fontColor('rgba(255,255,255,0.8)')
                .margin({ left: 12 })
            }
            .width('100%')
            .height(80)
            .justifyContent(FlexAlign.Center)
            .margin({ bottom: 12 })
          }

          // 输入框
          Row() {
            TextInput({ placeholder: '输入安全查询或语音描述...', text: $$this.inputText })
              .width('75%')
              .height(48)
              .backgroundColor('rgba(255,255,255,0.1)')
              .fontColor('#FFFFFF')
              .placeholderColor('rgba(255,255,255,0.5)')
              .borderRadius(24)
              .padding({ left: 16, right: 16 })
            
            // 语音按钮
            Stack() {
              Column()
                .width(52)
                .height(52)
                .backgroundColor(this.isListening ? '#F44336' : '#2196F3')
                .borderRadius(26)
                .shadow({
                  radius: 12,
                  color: this.isListening ? '#F4433666' : '#2196F366',
                  offsetX: 0,
                  offsetY: 0
                })
                .animation({
                  duration: 300,
                  curve: Curve.EaseInOut
                })
              
              Image($r('app.media.ic_mic'))
                .width(24)
                .height(24)
                .fillColor('#FFFFFF')
            }
            .width(52)
            .height(52)
            .onClick(() => {
              this.isListening = !this.isListening;
              if (this.isListening) {
                this.lightController.setLevel(SecurityLevel.CAUTION);
                // 模拟语音识别与处理
                setTimeout(() => {
                  this.lightController.setLevel(SecurityLevel.WARNING);
                  setTimeout(() => {
                    this.lightController.setLevel(SecurityLevel.DANGER);
                    setTimeout(() => {
                      this.chatMessages.push({ role: 'user', content: '帮我检查一下家里现在的安全状况' });
                      this.chatMessages.push({ 
                        role: 'agent', 
                        content: '检测到异常!客厅摄像头在15:32捕捉到不明移动物体,前门传感器触发了一次开门事件。建议立即查看实时监控画面,我已将态势等级提升至"危险"。' 
                      });
                      this.lightController.setLevel(SecurityLevel.DANGER);
                      this.isListening = false;
                    }, 1500);
                  }, 1500);
                }, 1000);
              } else {
                this.lightController.setLevel(SecurityLevel.SAFE);
              }
            })
          }
          .width('100%')
          .height(64)
          .padding({ left: 16, right: 16 })
          .justifyContent(FlexAlign.SpaceBetween)
        }
        .width('100%')
        .padding({ bottom: 24 })
      }
      .width('100%')
      .height('100%')
      .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
    }
    .width('100%')
    .height('100%')
  }

  private getLevelText(level: SecurityLevel): string {
    const map: Map<SecurityLevel, string> = new Map([
      [SecurityLevel.SAFE, '安全'],
      [SecurityLevel.CAUTION, '注意'],
      [SecurityLevel.WARNING, '警告'],
      [SecurityLevel.DANGER, '危险'],
      [SecurityLevel.EMERGENCY, '紧急']
    ]);
    return map.get(level) || '未知';
  }
}

代码亮点

  1. 全屏沉浸布局 :使用 expandSafeArea 将内容延伸至状态栏和底部区域
  2. 动态环境光晕:根据安全态势等级变化的大范围模糊光晕,营造氛围感
  3. 态势可视化反馈:安全态势处理过程中,光效、文字、动画三位一体反馈当前状态
  4. 语音交互模拟:完整的语音识别→分析→检测→告警状态流转演示

5.6 主页面集成(Index.ets)

将各组件整合为完整的应用入口。

typescript 复制代码
// entry/src/main/ets/pages/Index.ets
import { SecurityFloatNavigation } from '../components/SecurityFloatNavigation';
import { SecurityLightController, SecurityLevel } from '../components/SecurityLightEffect';
import { AlertCard } from '../components/AlertCard';
import router from '@ohos.router';

@Entry
@Component
struct Index {
  @State lightController: SecurityLightController = new SecurityLightController();
  @State currentTab: number = 0;
  
  // 模拟告警数据
  @State alertInfo = {
    level: 'warning',
    title: '前门异常检测',
    description: '前门传感器在14:35检测到异常振动,持续时间约12秒。建议检查门锁状态。',
    timestamp: '2026-06-26 14:35:22',
    location: '前门',
    deviceName: '前门传感器',
    imageUrl: ''
  };

  aboutToAppear(): void {
    this.lightController.setLevel(SecurityLevel.SAFE);
  }

  @Builder
  MonitorContentBuilder(): void {
    Stack() {
      // 模拟监控画面背景
      Column()
        .width('100%')
        .height('100%')
        .backgroundColor('#1A1A2E')
      
      // 监控网格线(模拟)
      Column() {
        ForEach([1, 2, 3, 4, 5], () => {
          Row() {
            ForEach([1, 2, 3, 4, 5], () => {
              Column()
                .width('20%')
                .height('20%')
                .border({ width: 0.5, color: 'rgba(255,255,255,0.05)' })
            })
          }
          .width('100%')
          .height('20%')
        })
      }
      .width('100%')
      .height('100%')
      
      // 安全态势光效轨迹
      Column()
        .width('60%')
        .height(4)
        .backgroundColor(this.lightController.getCurrentConfig().secondaryColor)
        .blur(8)
        .opacity(0.8)
        .position({ x: '20%', y: '50%' })
        .rotate({ angle: 15 })
        .shadow({
          radius: 16,
          color: this.lightController.getCurrentConfig().secondaryColor + '66',
          offsetX: 0,
          offsetY: 0
        })
        .animation({
          duration: 1000,
          curve: Curve.EaseInOut
        })
      
      // 告警卡片
      AlertCard({ alertInfo: this.alertInfo, lightController: this.lightController })
        .position({ y: 380 })
      
      // 语音助手悬浮按钮
      Stack() {
        Column()
          .width(64)
          .height(64)
          .backgroundColor(this.lightController.getCurrentConfig().secondaryColor)
          .blur(30)
          .borderRadius(32)
          .opacity(0.6)
          .animation({
            duration: 1000,
            curve: Curve.EaseInOut
          })
        
        Image($r('app.media.ic_mic'))
          .width(28)
          .height(28)
          .fillColor('#FFFFFF')
      }
      .width(64)
      .height(64)
      .position({ x: '85%', y: '75%' })
      .onClick(() => {
        router.pushUrl({ url: 'pages/SecurityVoicePage' });
      })
    }
    .width('100%')
    .height('100%')
  }

  build() {
    SecurityFloatNavigation({
      lightController: this.lightController,
      contentBuilder: this.MonitorContentBuilder.bind(this)
    })
  }
}

六、关键技术总结

6.1 悬浮导航适配清单

技术点 API/方法 应用场景
获取安全区高度 window.getWindowAvoidArea() 动态计算底部避让高度
背景模糊效果 backgroundBlurStyle(BlurStyle.REGULAR) 悬浮导航毛玻璃质感
背景滤镜 backdropFilter($r('sys.blur.20')) 精细模糊控制
扩展安全区 expandSafeArea([SafeAreaType.SYSTEM], [...]) 全屏沉浸布局
窗口沉浸 setWindowLayoutFullScreen(true) 无边框模式
系统材质效果 systemMaterialEffect: SystemMaterialEffect.IMMERSIVE HDS组件沉浸光感

6.2 沉浸光感最佳实践

  1. 光效层次设计:背景环境光晕→内容层→玻璃拟态组件的三层架构,避免光效互相干扰
  2. 态势语义化:每种安全态势等级对应独特的光色与节奏,建立用户心智模型
  3. 性能优化 :使用 animationiterations: -1 创建循环动画时,在页面不可见时暂停
  4. 无障碍支持:确保高对比度模式下玻璃拟态效果自动降级为纯色背景

6.3 安全态势光效映射

安全态势 光效颜色 脉冲速度 光晕半径 视觉语义
安全正常 柔和翠绿 4000ms 50px 平静守护
轻微注意 淡黄琥珀 2500ms 70px 需要关注
中度警告 橙色 1500ms 90px 存在异常
高度危险 红色 800ms 110px 危险预警
紧急告警 深红闪烁 400ms 130px 紧急状态

七、调试与适配建议

  1. 真机调试:玻璃拟态效果在模拟器上可能显示异常,建议在支持HarmonyOS 6的真机上测试光影效果
  2. 多设备适配:测试不同屏幕尺寸(手机/平板)下的悬浮导航位置与MiniBar显示
  3. 光效强度调节:提供用户设置入口,允许调节沉浸光效强度以适应不同环境光
  4. 低版本降级 :API 22及以下设备自动回退到传统 Tabs + 自定义玻璃导航栏

八、总结与展望

HarmonyOS 6的悬浮导航与沉浸光感特性为AI智能体应用提供了全新的交互范式。通过本文的实战案例,我们展示了如何:

  • 利用 setWindowLayoutFullScreenexpandSafeArea 实现真正的全屏沉浸体验
  • 使用 backgroundBlurStylebackdropFilter 创建玻璃拟态视觉效果
  • 构建智能避让安全区的悬浮导航组件,集成MiniBar扩展能力
  • 实现安全态势等级驱动的动态沉浸光效,让安防状态"看得见"
  • 打造语音交互的沉浸式界面,让用户感受到"与安全智能体面对面"的体验

这些技术不仅提升了安防类应用的视觉品质,更为AI智能体时代的安全交互设计提供了新的思路------让不可见的安全态势变得可见,让被动的监控变成主动的守护

未来,随着HarmonyOS生态的持续完善,我们期待看到更多基于悬浮导航与沉浸光感的创新应用,让每一次安全交互都成为一场视觉与智能的盛宴。


转载自:https://blog.csdn.net/u014727709/article/details/162357778

欢迎 👍点赞✍评论⭐收藏,欢迎指正