HarmonyOS Codelab の優れた例 - ショッピング アプリケーション、ワンタイム開発とマルチ デプロイの魅力を体験

 

1. サンプルの紹介

このコードラボはアダプティブ レイアウトとレスポンシブ レイアウトに基づいており、画面サイズの異なる携帯電話、折りたたみ式スクリーン、タブレット上でショッピング アプリケーションをさまざまなデザインで表示できるようにします。3 層のエンジニアリング構造を通じてコードを編成し、ワンタイムの開発とマルチエンドの展開を実現します。

携帯電話のランニング効果は図のとおりです。

 

折りたたみスクリーンの操作レンダリング:

 

タブレット操作レンダリング:

関連概念

  • 一度開発して複数の端末にデプロイ: 一連のコード プロジェクトを一度開発し、オンデマンドで複数の端末にデプロイします。開発者がさまざまな端末デバイス形式をサポートするアプリケーションを迅速かつ効率的に開発できるようにサポートします。
  • アダプティブ レイアウト: 外部コンテナのサイズが変化すると、要素は相対関係に従って自動的に変更され、外部コンテナのレイアウト機能に適応します。比率、固定アスペクト比、表示優先度などの相対関係。現在、アダプティブ レイアウト機能には、ストレッチ機能、イコライゼーション機能、プロポーション機能、ズーム機能、拡張機能、非表示機能、行折り返し機能の 7 種類があります。アダプティブ レイアウト機能により、外部コンテナのサイズに応じてインターフェイスの表示を継続的に変更できます。
  • レスポンシブ レイアウト: 外部コンテナのサイズが変更されると、ブレークポイント、グリッド、または特定の特性 (画面の向き、ウィンドウの幅、高さなど) に基づいて要素が自動的に変更され、外部コンテナのレイアウト機能に適応できます。現在、レスポンシブ レイアウト機能には、ブレークポイント、メディア クエリ、グリッド レイアウトの 3 種類があります。
  • GridRow : グリッド レイアウト シナリオでグリッド サブコンポーネント (GridCol) とともにのみ使用できるグリッド コンテナー コンポーネント。
  • GridCol : グリッド サブコンポーネント。グリッド コンテナー コンポーネント (GridRow) のサブコンポーネントとして使用する必要があります。

完全な例: gitee ソース コード アドレス

2. 環境構築

まずは HarmonyOS 開発環境の構築を完了する必要がありますので、以下の手順を参照してください。

ソフトウェア要件

  • DevEco Studioバージョン: DevEco Studio 3.1 リリース以降。
  • HarmonyOS SDKバージョン: API バージョン 9 以降。

ハードウェア要件

  • デバイスの種類: Huawei 携帯電話、または DevEco Studio で実行されている Huawei 携帯電話デバイス シミュレータ。
  • HarmonyOS システム: 3.1.0 開発者リリース以降。

環境設定

  1. DevEco Studio をインストールします。詳細については、「ソフトウェアのダウンロードとインストール」を参照してください
  2. DevEco Studio 開発環境をセットアップします。DevEco Studio 開発環境はネットワーク環境に依存します。ツールを通常に使用するには、ネットワークに接続する必要があります。次の 2 つの状況に応じて開発環境を構成できます。
  1. 開発者は、次のリンクを参照して、デバイス デバッグの関連構成を完了できます。

3. コード構造の解釈

この Codelab ではコア コードのみを説明します。Common はパブリック機能層、feature は機能モジュール層、この例では 6 つのモジュールに分かれています、product はプロダクト層です。完全なコードについては、ソース コードのダウンロードまたは gitee で提供されます。

├──common/src/main/ets               // 公共能力层
│  ├──bean
│  │  ├──CommodityModel.ets          // 商品数据实体类
│  │  ├──OrderModel.ets              // 订单数据实体类
│  │  └──ProductModel.ets            // 购物车商品数据实体类
│  ├──components
│  │  ├──CommodityList.ets           // 商品列表组件
│  │  ├──CounterProduct.ets          // 数量加减组件
│  │  └──EmptyComponent.ets          // 无数据显示组件
│  ├──constants
│  │  ├──BreakpointConstants.ets     // 断点常量类
│  │  ├──GridConstants.ets           // 栅格常量类
│  │  └──StyleConstants.ets          // 样式常量类
│  ├──utils
│  │  ├──BreakpointSystem.ets        // 断点工具类
│  │  ├──CommonDataSource.ets        // 数据封装类
│  │  ├──LocalDataManager.ets        // 数据操作管理类
│  │  ├──Logger.ets.ets              // 日志工具类
│  │  └──Utils.ets                   // 方法工具类
│  └──viewmodel
│     └──ShopData.ets                // 商品应用数据
├──features                          // 功能模块层
│  ├──commoditydetail/src/main/ets   // 商品详情内容区
│  │  ├──bean
│  │  │  └──TypeModel.ets            // 实体类
│  │  ├──components
│  │  │  ├──CapsuleGroupButton.ets   // 自定义按钮组件
│  │  │  ├──CommodityDetail.ets      // 商品详情组件
│  │  │  └──SpecificationDialog.ets  // 商品规格弹框
│  │  ├──constants
│  │  │  └──CommodityConstants.ets   // 商品详情区常量类
│  │  └──viewmodel
│  │     └──CommodityDetailData.ets  // 商品详情数据类
│  ├──home/src/main/ets              // 首页内容区
│  │  ├──components
│  │  │  └──Home.ets                 // 首页内容组件
│  │  └──viewmodel
│  │     └──HomeData.ets             // 首页数据
│  ├──newproduct/src/main/ets        // 新品内容区
│  │  ├──components
│  │  │  └──NewProduct.ets           // 新品内容组件
│  │  └──viewmodel
│  │     └──NewProductData.ets       // 新品数据
│  ├──orderdetail/src/main/ets       // 订单相关内容区
│  │  ├──components
│  │  │  ├──AddressInfo.ets          // 收件人信息组件
│  │  │  ├──CommodityOrderItem.ets   // 商品订单信息组件
│  │  │  ├──CommodityOrderList.ets   // 商品订单列表组件
│  │  │  ├──ConfirmOrder.ets         // 确认订单组件
│  │  │  ├──HeaderBar.ets            // 标题组件
│  │  │  ├──OrderDetailList.ets      // 订单分类列表组件
│  │  │  ├──OrderListContent.ets     // 订单分类列表内容组件
│  │  │  └──PayOrder.ets             // 支付订单组件
│  │  ├──constants
│  │  │  └──OrderDetailConstants.ets // 订单区常量类
│  │  └──viewmodel
│  │     └──OrderData.ets            // 订单数据
│  ├──personal/src/main/ets          // 我的内容区
│  │  ├──bean
│  │  │  └──IconButtonModel.ets      // 按钮图标实体类
│  │  ├──components
│  │  │  ├──IconButton.ets           // 图片按钮组件
│  │  │  ├──LiveList.ets             // 直播列表组件
│  │  │  └──Personal.ets             // 我的内容组件
│  │  ├──constants
│  │  │  └──PersonalConstants.ets    // 我的常量类
│  │  └──viewmodel
│  │     └──PersonalData.ets         // 我的数据
│  └──shopcart/src/main/ets          // 购物车内容区
│     ├──components
│     │  └──ShopCart.ets             // 购物车内容组件
│     └──constants
│        └──ShopCartConstants.ets    // 购物车常量类
└──products                          // 产品层
   └──phone/src/main/ets             // 支持手机、平板
      ├──constants
      │  └──PageConstants.ets        // 页面常量类
      ├──entryability
      │  └──EntryAbility.ets          // 程序入口类
      ├──pages
      │  ├──CommodityDetailPage.ets  // 订单详情页
      │  ├──ConfirmOrderPage.ets     // 确认订单页
      │  ├──MainPage.ets             // 主页
      │  ├──OrderDetailListPage.ets  // 订单分类列表页
      │  ├──PayOrderPage.ets         // 支付订单页
      │  └──SplashPage.ets           // 启动过渡页
      └──viewmodel
         └──MainPageData.ets         // 主页数据

4. アプリケーションのメインフレームワーク

4.1 スタートページ

プロジェクト ページ ディレクトリで Index.ets を選択し、右クリック > [リファクタリング] > [名前の変更] を選択して、名前を SplashPage.ets に変更します。名前を変更した後、プロジェクトのentryabilityディレクトリにあるEntryAbility.etsファイルのwindowStage.loadContentメソッドの最初のパラメータをpages/SplashPageに変更します。ホームページにジャンプするために、ページの定期関数 aboutToAppear に 2 秒のスケジュールされたタスクを追加します。

// EntryAbility.ets
windowStage.loadContent('pages/SplashPage', (err, data) => {
                     
                     
  if (err.code) {
                     
                     
    ...
  }
});

// SplashPage.ets
build() {
                     
                     
  Column() {
                     
                     
    ...
  }
  .height(StyleConstants.FULL_HEIGHT)
  .width(StyleConstants.FULL_WIDTH)
  .backgroundColor($r('app.color.page_background'))
}

aboutToAppear() {
                     
                     
  this.breakpointSystem.register();
  this.timeOutId = setTimeout(() => {
                     
                     
    router.replaceUrl({
                     
                      url: PageConstants.MAIN_PAGE_URL })
      .catch(err => {
                     
                     
        Logger.error(JSON.stringify(err));
      })
  }, PageConstants.DELAY_TIME);
}

aboutToDisappear() {
                     
                     
  this.breakpointSystem.unregister();
  clearTimeout(this.timeOutId);
}

携帯電話の操作レンダリング:

折りたたみスクリーンの操作レンダリング:

タブレット操作レンダリング:

4.2 ホームページ

このコードラボのホームページは、タブ コンテナ コンポーネントと 4 つの TabContent サブコンポーネントで構成されており、4 つの TabContent タブのコンテンツ ビューは、Home、New Product、ShopCart、および Personal です。ユーザーの使用シナリオに応じて、レスポンシブレイアウトのメディアクエリを通じて、アプリケーションのウィンドウ幅の変化を監視し、現在のアプリケーションのブレークポイント値を取得し、タブのタブ位置を設定し、タブレットなどのLGブレークポイントはサイドバーを表示し、その他のブレークポイントを表示します。下部のバーが表示されます。

/// MainPage.ets
build() {
                         
                         
  Column() {
                         
                         
    Tabs({
                         
                         
      barPosition: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
        BarPosition.Start : BarPosition.End,
      index: this.currentPageIndex
    }) {
                         
                                
    ...  
    .barWidth(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
      $r('app.float.bar_width') : StyleConstants.FULL_WIDTH)
    .barHeight(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
      StyleConstants.SIXTY_HEIGHT : $r('app.float.vp_fifty_six'))
    .vertical(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG)
  }
  .backgroundColor($r('app.color.page_background'))
}

ホームページの表示:

5. ページ紹介

5.1 「ホーム」タブページ

ホーム ページ タブは、アダプティブ レイアウトのイコライゼーションおよびストレッチ機能を通じて検索ボックスやカテゴリなどのレイアウトを実現し、レスポンシブ レイアウトのメディア クエリおよびブレークポイント機能を通じてカルーセル画像と製品リストの数を設定します。

レスポンシブ レイアウトのメディア クエリを通じて、アプリケーション ウィンドウの幅の変化を監視し、現在のアプリケーションのブレークポイント値を取得し、製品リストの列とカルーセル画像の数を設定します。lg ブレークポイントは 4 列と 3 つのカルーセル画像を表示します。md ブレークポイントは 3 列を表示します。および 2 つのカルーセル、sm ブレークポイントは 2 つの列と 1 つのカルーセルを表示します。

// Home.ets
@Builder CustomSwiper() {
                             
                             
  Swiper() {
                             
                             
    ForEach(swiperImage, (item: Resource) => {
                             
                             
      Image(item)
        .width(StyleConstants.FULL_WIDTH)
        .aspectRatio(StyleConstants.IMAGE_ASPECT_RATIO)
    }, item => JSON.stringify(item))
  }
  .itemSpace(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? 0 :
    StyleConstants.ITEM_SPACE)
  .indicator(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM)
  .displayCount(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
    StyleConstants.DISPLAY_THREE :
    (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD ? StyleConstants.DISPLAY_TWO :
    StyleConstants.DISPLAY_ONE))
}

// Home.ets
CommodityList({
                             
                             
  commodityList: $commodityList,
  column: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? StyleConstants.DISPLAY_FOUR :
    (this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD ?
    StyleConstants.DISPLAY_THREE : StyleConstants.DISPLAY_TWO),
  onClickItem: (data: Commodity) => this.onClickItem(data)
})

// CommodityList.ets
build() {
                             
                             
  if (this.commodityList.length > 0) {
                             
                             
    List({ space: StyleConstants.TWELVE_SPACE }) {
                             
                             
      LazyForEach(new CommonDataSource(this.commodityList), (item: Commodity) => {
                             
                             
        ...
      }, item => JSON.stringify(item))
    }
    ...
    .lanes(this.column)
  } else {
                             
                             
    EmptyComponent({
                             
                              outerHeight: StyleConstants.FIFTY_HEIGHT })
  }
}

アダプティブ レイアウトのイコライゼーション機能を使用して、Flex レイアウトで主軸の位置合わせを FlexAlign.SpaceAround に設定し、サイクル内でレンダリングされるコンポーネント間の距離、つまり最初の要素と線の先頭の間の距離が同じになるようにします。最後の要素と行の終端の間の距離 (隣接する要素間の距離の半分)。

// Home.ets
@Builder ActivityTitle() {
                             
                             
  Flex({ justifyContent: FlexAlign.SpaceAround }) {
                             
                             
    ForEach(activityTitle, (item: ActivityTitleModel, index: number) => {
                             
                             
      Flex({
                             
                             
        direction: FlexDirection.Column,
        justifyContent: FlexAlign.Center,
        alignItems: ItemAlign.Center
      }) {
                             
                             
        ...
      }
    }, item => JSON.stringify(item))
  }
  ...
}

携帯電話の操作レンダリング:

屏風操作レンダリング

タブレット操作レンダリング

5.2 新製品タブページ

新製品タブ ページはカルーセル、分類、新製品リストで構成されており、レスポンシブ レイアウトのメディア クエリ、ブレークポイント機能、アダプティブ レイアウトのイコライゼーション機能を通じて、デバイス タイプごとに異なる効果を表示し、ホームページと同じロジックです。

レスポンシブ レイアウトのメディア クエリを通じて、アプリケーション ウィンドウの幅の変化を監視し、現在のアプリケーションのブレークポイント値を取得し、新しい製品リストを設定します。sm ブレークポイントは 2 列を表示し、md および lg ブレークポイントは 3 列を表示します。 。

// NewProduct.ets
@Builder ProductList() {
                               
                               
  List({ space: StyleConstants.TWELVE_SPACE }) {
                               
                               
    LazyForEach(new CommonDataSource(productData), (item: ProductDataModel) => {
                               
                               
      ListItem() {
                               
                               
        ...
    }, item => JSON.stringify(item))
  }
  .lanes(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ?
    StyleConstants.DISPLAY_TWO : StyleConstants.DISPLAY_THREE)
  .padding({
                               
                                left: $r('app.float.vp_twelve'), right: $r('app.float.vp_twelve') })
}

携帯電話の操作レンダリング:

屏風操作レンダリング

タブレット操作レンダリング

5.3 ショッピングカートタブ

ショッピング カート タブ ページは、ショッピング カート リストと商品リストで構成されます。商品リストの実装ロジックは、ホームページの商品リストと同じです。ショッピング カート リストは、アダプティブ レイアウトの均等化機能を使用して実装されます。

// ShopCart.ets
@Builder CartItem(item: Product, index: number) {
                                 
                                 
  Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {
                                 
                                 
    ...
    Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceAround }) {
                                 
                                 
      Text($r('app.string.commodity_piece_description', item.name, item.description))
        ...
      Text(`${Object.values(item.specifications).join(',')}`)
        ...
      Flex({ justifyContent: FlexAlign.SpaceBetween }) {
                                 
                                 
        Text() {
                                 
                                 
          ...
        }

        CounterProduct({
                                 
                                 
          count: item.count,
          onNumberChange: (num: number) => {
                                 
                                 
            this.onChangeCount(num, item);
          }
        })
      }
    }
    ...
  }
}

携帯電話の操作レンダリング:

屏風操作レンダリング

タブレット操作レンダリング

5.4 私のタブ

私のタブ ページは主に個人情報、注文、テキストと画像のボタン、ライブ ブロードキャスト リストで構成されます。ライブ ブロードキャスト リストの実装計画は、ホームページの製品リストと同じです。その他は、アダプティブ レイアウトの均等化機能を使用します。 Flex レイアウトの主軸の位置合わせは FlexAlign.SpaceAround に設定されます。

// Personal.ets
@Builder Order() {
                                   
                                   
  Flex({direction: FlexDirection.Column}) {
                                   
                                   
    Flex({
                                   
                                   
      justifyContent: FlexAlign.SpaceBetween,
      alignItems: ItemAlign.Center
    }) {
                                   
                                   
      Text($r('app.string.order_mine'))
        .fontSize($r('app.float.middle_font_size'))
      Row() {
                                   
                                   
        ...
      }
      ...
      })
    }
  Flex({
                                   
                                   
    justifyContent: FlexAlign.SpaceAround,
    alignItems: ItemAlign.Center
  }) {
                                   
                                   
    ForEach(this.orderIconButton, (iconButton: IconButtonModel) => {
                                   
                                   
      IconButton({
                                   
                                   
        props: iconButton,
        click: this.onOrderButtonClick.bind(this, iconButton.key)
      })
    }, (iconButton) => JSON.stringify(iconButton))
  }
  .width(StyleConstants.FULL_WIDTH)
}

@Builder IconDock(buttons: IconButtonModel[]) {
                                   
                                   
  Flex({
                                   
                                   
    justifyContent: FlexAlign.SpaceAround,
    alignItems: ItemAlign.Center
  }) {
                                   
                                   
    ForEach(buttons, (iconButton: IconButtonModel) => {
                                   
                                   
      IconButton({
                                   
                                   
        props: iconButton
      })
    }, (iconButton) => JSON.stringify(iconButton))
  }
  .height($r('app.float.icon_dock_height'))
  .padding($r('app.float.vp_twelve'))
  .cardStyle()
}

携帯電話の操作レンダリング:

折りたたみスクリーンの操作レンダリング:

タブレット操作レンダリング:

5.5 製品詳細ページ

製品詳細ページは全体として、カルーセル画像、製品情報、下部ボタン バーで構成されています。レスポンシブ レイアウト機能を備えたグリッド レイアウトを通じて、デバイスの種類ごとに異なる効果を表示できます。また、アダプティブ レイアウトの伸縮機能を通じて、 flexGrow 属性を設定できます。ボタンは下部にあります。

  • sm ブレークポイントの下では、カルーセル画像が 4 つのグリッドを占め、製品情報が 4 つのグリッドを占め、下部のボタン バーが 4 つのグリッドを占めます。
  • md ブレークポイントの下では、カルーセル画像が 8 グリッドを占め、製品情報が 8 グリッドを占め、下部のボタン バーが 8 グリッドを占めます。
  • lg ブレークポイントの下では、カルーセル画像は 12 グリッドを占め、製品情報は 2 グリッド オフセットの 8 グリッドを占め、一番下のボタン バーは 2 グリッド オフセットの 8 グリッドを占めます。

// CommodityDetail.ets
build() {
                                     
                                     
  Stack({ alignContent: Alignment.TopStart }) {
                                     
                                     
    Flex({ direction: FlexDirection.Column }) {
                                     
                                     
      Scroll() {
                                     
                                     
        GridRow({
                                     
                                     
          columns: {
                                     
                                     
            sm: GridConstants.COLUMN_FOUR,
            md: GridConstants.COLUMN_EIGHT,
            lg: GridConstants.COLUMN_TWELVE
          },
          gutter: GridConstants.GUTTER_TWELVE
        }) {
                                     
                                     
          GridCol({
                                     
                                     
            span: {
                                     
                                     
              sm: GridConstants.SPAN_FOUR,
              md: GridConstants.SPAN_EIGHT,
              lg: GridConstants.SPAN_TWELVE }
          }) {
                                     
                                     
            this.CustomSwiper(this.info.images)
          }
          GridCol({
                                     
                                     
            span: {
                                     
                                     
              sm: GridConstants.SPAN_FOUR,
              md: GridConstants.SPAN_EIGHT,
              lg: GridConstants.SPAN_EIGHT
            },
            offset: { lg: GridConstants.OFFSET_TWO }
          }) {
                                     
                                     
            Column() {
                                     
                                     
              ...
            }
          }
        }
      }
      .flexGrow(StyleConstants.FLEX_GROW)
      GridRow({
                                     
                                     
        columns: {
                                     
                                     
          sm: GridConstants.COLUMN_FOUR,
          md: GridConstants.COLUMN_EIGHT,
          lg: GridConstants.COLUMN_TWELVE
        },
        gutter: GridConstants.GUTTER_TWELVE
      }) {
                                     
                                     
        GridCol({
                                     
                                     
          span: {
                                     
                                     
            sm: GridConstants.SPAN_FOUR,
            md: GridConstants.SPAN_EIGHT,
            lg: GridConstants.SPAN_EIGHT
          },
          offset: { lg: GridConstants.OFFSET_TWO } }) {
                                     
                                     
          this.BottomMenu()
        }
      }
    }
    ...
  }
}

携帯電話の操作レンダリング:

折りたたみスクリーンの操作レンダリング:

タブレット操作レンダリング:

5.6 注文確認ページ

注文確認ページは、上部の受領情報、下部の注文情報、合計金額、および注文送信ボタンで構成されています。レスポンシブなグリッド レイアウトを通じて、デバイスの種類ごとに異なる効果を表示できます。アダプティブ レイアウト。合計価格と注文の送信ボタンが一番下になるように flexGrow プロパティを設定します。

  • sm ブレークポイントの下では、上部の受信情報と注文情報が 4 グリッドを占め、下部の合計価格が 2 グリッドを占め、下部の注文送信ボタンが 2 グリッドを占めます。
  • md ブレークポイントの下では、上部の受領情報と注文情報が 8 グリッドを占め、下部の合計価格が 2 グリッドを占め、下部のボタンが 3 グリッドを占め、3 グリッドずつオフセットされます。
  • lg ブレークポイントの下では、上部の受領情報と注文情報は 8 グリッドを占め、2 グリッドずつオフセットされ、下部の合計価格は 2 グリッドを占め、2 グリッドずつオフセットされ、下部のボタンは 3 グリッドを占め、オフセットされます。 3グリッドごとに。

// ConfirmOrder.ets
build() {
                                       
                                       
  Flex({ direction: FlexDirection.Column }) {
                                       
                                       
    HeaderBar({
                                       
                                       
      ...
    })
    Column(){
                                       
                                       
      Scroll() {
                                       
                                       
        GridRow({
                                       
                                       
          columns: {
                                       
                                       
            sm: GridConstants.COLUMN_FOUR,
            md: GridConstants.COLUMN_EIGHT,
            lg: GridConstants.COLUMN_TWELVE
            }
          }) {
                                       
                                       
          GridCol({
                                       
                                       
            span: {
                                       
                                       
              sm: GridConstants.SPAN_FOUR,
              md: GridConstants.SPAN_EIGHT,
              lg: GridConstants.SPAN_EIGHT
            },
            offset: { lg: GridConstants.OFFSET_TWO }
          }) {
                                       
                                       
            Column() {
                                       
                                       
              AddressInfo()
              CommodityOrderList()
            }
          }
        }
      }
      .scrollBar(BarState.Off)
    }
    .flexGrow(StyleConstants.FLEX_GROW)
    .padding({
                                       
                                        left: $r('app.float.vp_twelve'), right: $r('app.float.vp_twelve') })
    GridRow({
                                       
                                       
      columns: {
                                       
                                       
        sm: GridConstants.COLUMN_FOUR,
        md: GridConstants.COLUMN_EIGHT,
        lg: GridConstants.COLUMN_TWELVE
      },
      gutter: GridConstants.GUTTER_TWELVE
    }) {
                                       
                                       
      GridCol({
                                       
                                       
        span: {
                                       
                                       
          sm: GridConstants.SPAN_TWO,
          md: GridConstants.SPAN_TWO,
          lg: GridConstants.SPAN_TWO
        },
        offset: { lg: GridConstants.OFFSET_TWO }
      }) {
                                       
                                       
        Text($r('app.string.bottom_bar_amount', this.amount))
        ...
      }
      GridCol({
                                       
                                       
        span: {
                                       
                                       
          sm: GridConstants.SPAN_TWO,
          md: GridConstants.SPAN_THREE,
          lg: GridConstants.SPAN_THREE
        },
        offset: {
                                       
                                       
          md: GridConstants.OFFSET_THREE,
          lg: GridConstants.OFFSET_THREE
        }
      }) {
                                       
                                       
        Button($r('app.string.bottom_bar_button'))
          ...
      }
    }
    ...
  }
  ...
}

携帯電話の操作レンダリング:

折りたたみスクリーンの操作レンダリング:

タブレット操作レンダリング:

5.7 注文支払いページ

注文支払いページは、上部の注文情報と下部の支払いボタンで構成されており、レスポンシブ レイアウトのグリッド レイアウトを使用することで、デバイスの種類ごとに異なる効果を表示でき、アダプティブ レイアウトの伸縮機能により、下部の支払いボタンを有効にするために flexGrow 属性が設定されています。

  • sm ブレークポイントの下では、上位の注文情報が 4 グリッドを占め、下位の支払いボタンは 2 グリッドオフセットされた 2 グリッドを占めます。
  • md ブレークポイントの下では、上部の注文情報が 8 グリッドを占め、下部の支払いボタンは 6 グリッドオフセットされた 2 グリッドを占めます。
  • lg ブレークポイントの下では、上位の情報は 2 グリッド離れた 8 グリッドを占め、下位の支払いボタンは 8 グリッド離れた 2 グリッドを占めます。

// PayOrder.ets
build() {
                                         
                                         
  Flex({ direction: FlexDirection.Column }) {
                                         
                                         
    HeaderBar({
                                         
                                         
      ...
    })
    Stack({ alignContent: Alignment.TopStart }) {
                                         
                                         
      ...
      Column() {
                                         
                                         
        Scroll() {
                                         
                                         
          GridRow({
                                         
                                         
            columns: {
                                         
                                         
              sm: GridConstants.COLUMN_FOUR,
              md: GridConstants.COLUMN_EIGHT,
              lg: GridConstants.COLUMN_TWELVE
            }
          }) {
                                         
                                         
            GridCol({
                                         
                                         
              span: {
                                         
                                         
                sm: GridConstants.SPAN_FOUR,
                md: GridConstants.SPAN_EIGHT,
                lg: GridConstants.SPAN_EIGHT
              },
              offset: { lg: GridConstants.OFFSET_TWO }
            }) {
                                         
                                         
              Column() {
                                         
                                         
                this.OrderStatus()
                ...
              }
            }
          }
        }
        .scrollBar(BarState.Off)
      }
      .padding({
                                         
                                          left: $r('app.float.vp_twelve'), right: $r('app.float.vp_twelve') })
    }
    .flexGrow(StyleConstants.FLEX_GROW)

    GridRow({
                                         
                                         
      columns: {
                                         
                                         
        sm: GridConstants.COLUMN_FOUR,
        md: GridConstants.COLUMN_EIGHT,
        lg: GridConstants.COLUMN_TWELVE
      }
    }) {
                                         
                                         
      GridCol({
                                         
                                         
        span: {
                                         
                                         
          sm: GridConstants.SPAN_TWO,
          md: GridConstants.SPAN_TWO,
          lg: GridConstants.SPAN_TWO
        },
        offset: {
                                         
                                         
          sm: GridConstants.OFFSET_TWO,
          md: GridConstants.OFFSET_SIX,
          lg: GridConstants.OFFSET_EIGHT
        }
      }) {
                                         
                                         
        this.BottomBar()
      }
    }
  }
  ...
}

携帯電話の操作レンダリング:

折りたたみスクリーンの操作レンダリング:

タブレット操作レンダリング:

5.8 注文リストページ

注文リスト ページの全体的なレイアウトは、レスポンシブ レイアウトのグリッド レイアウトを使用して、デバイスの種類ごとに異なる表示効果を実現します。

  • sm ブレークポイントの下では、UX 全体が 4 グリッドを占めます。
  • md ブレークポイントでは、UX 全体が 8 グリッドを占めます。
  • lg ブレークポイントの下では、UX 全体が 2 グリッドオフセットされた 8 グリッドを占めます。

// OrderListContent.ets
build() {
                                           
                                           
  Column() {
                                           
                                           
    Scroll() {
                                           
                                           
      GridRow({
                                           
                                           
        columns: {
                                           
                                           
          sm: GridConstants.COLUMN_FOUR,
          md: GridConstants.COLUMN_EIGHT,
          lg: GridConstants.COLUMN_TWELVE
        }
      }) {
                                           
                                           
        GridCol({
                                           
                                           
          span: {
                                           
                                           
            sm: GridConstants.SPAN_FOUR,
            md: GridConstants.SPAN_EIGHT,
            lg: GridConstants.SPAN_EIGHT
          },
          offset: { lg: GridConstants.OFFSET_TWO }
        }) {
                                           
                                           
          Column() {
                                           
                                           
            ...
          }
        }
      }
    }
    .scrollBar(BarState.Off)
  }
  ...
}

携帯電話の操作レンダリング:

折りたたみスクリーンの操作レンダリング:

タブレット操作レンダリング:

6. まとめ

この Codelab の学習を完了し、次の知識ポイントを学習しました。

  1. さまざまな画面サイズのデバイスに対応する 1 つの開発および複数展開ページのデザインを完了します。
  2. 3層のエンジニアリング構造に従ってモジュールを分割し、コードを整理します。
  3. アダプティブ レイアウト、レスポンシブ レイアウト、グリッド レイアウトを通じて、ワンタイム開発とマルチ展開が実現されます。

おすすめ

転載: blog.csdn.net/HarmonyOSDev/article/details/132532705