#HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片 原创

奥尼5354
发布于 2025-3-10 22:31
浏览
0收藏

简介

服务卡片框架提供了FormExtensionAbility基类,通过继承此基类,实现调用服务卡片的生命周期函数,来实现具体卡片的功能。
开放了属性动画和显式动画,增加了自定义绘制的能力,可以使用Canvas画布组件自定义绘制和构建更多样的显示和交互效果。允许卡片中运行逻辑代码,业务逻辑可以在卡片内部自闭环。

不支持功能

  • 不支持导入共享包。
  • 不支持native语言,仅支持声明式范式的部分组件、事件、动效、数据管理、状态管理和API能力。
  • 暂不支持极速预览。
  • 暂不支持setTimeOut。

工程目录

 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区

新建流程(静态服务窗口)

1.选择静态服务窗口
 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区

2.选择项目模板
 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区
3.设置卡片名称、简介、模块大小等

 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区
4.根据选择的样板,自动添加卡片项目相关文件。
 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区
5.默认的预览视图
 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区
6.需要修改卡片配置,可以去form_config.json中设置

卡片事件(静态卡片)

 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区

案例代码

实现效果
 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区

项目架构

 #HarmonyOS NEXT体验官#【HarmonyOSNext】静态服务卡片-鸿蒙开发者社区

DateUtil.ets

export class DateUtil {
  /**
   * 返回时间
   * @param date
   * @returns 14:53样式的时间
   */
  static ToTime(date: Date): string {
    if (date == null) {
      return "";
    }
    return `${DateUtil.PrefixInteger(date.getHours(), 2)}:${DateUtil.PrefixInteger(date.getMinutes(), 2)}`
  }

  /**
   * 返回月份和周几
   * @param date
   * @returns 返回6月17日(周一)的样式
   */
  static ToMonthDay(date: Date): string {
    if (date == null) {
      return "";
    }
    const weekDays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
    return `${date.getMonth() + 1}月${date.getDate()}(${weekDays[date.getDay()]})`
  }

  static PrefixInteger(num: number, length: number) {
    return (Array(length).join('0') + num).slice(-length);
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

Ticket_WidgetCard.ets

import { TicketShow_ViewModel } from '../viewmodel/TicketShow_ViewModel'
import { TicketShow_View } from '../view/TicketShow_view'

@Entry
@Component
struct Ticket_WidgetCard {
  /*
   * action的类型
   */
  readonly ACTION_TYPE: string = 'router';
  /*
   * action为router / call 类型时跳转的UIAbility名
   */
  readonly ABILITY_NAME: string = 'EntryAbility';
  /*
   * The message.
   */
  readonly MESSAGE: string = 'add detail';
  /*
   * The height percentage setting.
   */
  readonly FULL_HEIGHT_PERCENT: string = '100%';
  @State ticketShowVM: TicketShow_ViewModel = new TicketShow_ViewModel(
    "G6357",
    new Date(2024, 5, 17, 14, 33),
    new Date(2024, 5, 17, 20, 0),
    "凤凰古城",
    "广州",
    "二等车 06车 05F号");

  build() {
    FormLink({
      action: this.ACTION_TYPE,
      abilityName: this.ABILITY_NAME,
      params: {
        message: this.MESSAGE
      }
    }) {
      Stack({ alignContent: Alignment.BottomEnd }) {
        TicketShow_View({
          viewModel: this.ticketShowVM
        })
          .margin(10)
        Image($r('app.media.railway'))
          .height(80)
          .opacity(0.3)
          .margin({ bottom: 10, right: 20 })
      }
      .height(this.FULL_HEIGHT_PERCENT)
      .width("100%")
      .backgroundColor('#00000000')
      .linearGradient({
        angle: 90,
        colors: [["#1f82ca", 0.0], ["#24c8df", 1.0]]
      })
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.

TicketShow_view.ets

import { DateUtil } from '../../common/DateUtil';
import { TicketShow_ViewModel, TicketStage } from '../viewmodel/TicketShow_ViewModel'

@Component
export struct TicketShow_View {
  @ObjectLink viewModel: TicketShow_ViewModel
  /**
   * 字体颜色
   */
  readonly TEXT_COLOR: ResourceColor = Color.White;

  build() {
    Column() {
      Row() {
        Column() {
          Text(DateUtil.ToTime(this.viewModel.BoardingTime))
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor(this.TEXT_COLOR)

          Text(this.viewModel.BoardingAddress)
            .fontSize(14)
            .margin({ top: 5 })
            .fontColor(this.TEXT_COLOR)
        }
        .height("100%")
        .layoutWeight(1)
        .alignItems(HorizontalAlign.Start)
        .justifyContent(FlexAlign.Start)

        Column() {
          Text(this.viewModel.Id)
            .fontSize(14)
            .fontColor(this.TEXT_COLOR)
          Path()
            .commands('M0 0 L300 0 L270 -10 L270 0 Z')
            .margin({ top: 4 })
            .strokeWidth(1)
            .fill(this.TEXT_COLOR)
            .stroke(this.TEXT_COLOR)
          Text(DateUtil.ToMonthDay(this.viewModel.BoardingTime))
            .fontSize(12)
            .margin({ top: 5 })
            .fontColor(this.TEXT_COLOR)
        }
        .height("100%")
        .layoutWeight(2)
        .justifyContent(FlexAlign.Start)

        Column() {
          Text(DateUtil.ToTime(this.viewModel.ArrivalTime))
            .fontSize(20)
            .fontWeight(FontWeight.Bold)
            .fontColor(this.TEXT_COLOR)
          Text(this.viewModel.ArrivalAddress)
            .fontSize(14)
            .margin({ top: 5 })
            .fontColor(this.TEXT_COLOR)
        }
        .height("100%")
        .layoutWeight(1)
        .alignItems(HorizontalAlign.End)
        .justifyContent(FlexAlign.Start)
      }
      .width("100%")
      .layoutWeight(2)
      .margin({ top: 20 })

      Column() {
        Text(this.viewModel.Position)
          .fontSize(12)
          .fontColor(this.TEXT_COLOR)
        Row() {
          Text("状态:")
            .fontSize(12)
            .fontColor(this.TEXT_COLOR)
          Text(TicketStage[this.viewModel.Stage])
            .fontSize(12)
            .fontColor(this.TEXT_COLOR)
        }
        .margin({ top: 5 })
      }
      .width("100%")
      .layoutWeight(1)
      .alignItems(HorizontalAlign.Start)
      .justifyContent(FlexAlign.Start)
    }
    .width("100%")
    .height("100%")

  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.

TicketShow_ViewModel.ets

/**
 * 展示组件的ViewModel
 */
@Observed
export class TicketShow_ViewModel {
  /**
   * 火车编号
   */
  public Id: string = '';
  /**
   * 开始时间
   */
  public BoardingTime: Date = new Date();
  /**
   * 到达时间
   */
  public ArrivalTime: Date = new Date();
  /**
   * 起始站
   */
  public BoardingAddress: string = "";
  /**
   * 终点站
   */
  public ArrivalAddress: string = "";
  /**
   * 座位
   */
  public Position: string = "";
  /**
   * 状态
   */
  public Stage: TicketStage = TicketStage.待车

  constructor(
    id: string,
    boardingTime: Date,
    arrivalTime: Date,
    boardingAddress: string,
    arrivalAddress: string,
    position: string) {
    this.Id = id;
    this.BoardingTime = boardingTime;
    this.BoardingAddress = boardingAddress;
    this.ArrivalTime = arrivalTime;
    this.ArrivalAddress = arrivalAddress;
    this.Position = position;
  }

  public isDraft(): boolean {
    return true;
  }
}

/**
 * 车票状态
 */
export enum TicketStage {
  待车,
  正在检票,
  停止检票
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.

注意

里面的图片是需要自己去下载的,暂未实现数据和程序联动

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐