鸿蒙OS开发:典型页面场景【一次开发,多端部署】实战(应用市场首页)

电子说

1.3w人已加入

描述

一多应用市场首页

介绍

本示例展示了应用市场首页,页面中包括Tab栏、运营横幅、精品应用、精品游戏等。

本示例使用[一次开发多端部署]中介绍的自适应布局能力和响应式布局能力进行多设备(或多窗口尺寸)适配,保证应用在不同设备或不同窗口尺寸下可以正常显示。

用到了媒体查询接口[@ohos.mediaquery]。

效果预览

本示例在预览器中的效果:

鸿蒙

本示例在开发板上运行的效果:

鸿蒙

使用说明:

  1. 启动应用,可以查看本应用在全屏状态下的显示效果。
  2. 在应用顶部,下滑出现窗口操作按钮。(建议通过外接鼠标操作,接入鼠标只需要将鼠标移动至顶部即可出现窗口)
  3. 点击悬浮图标,将应用悬浮在其它界面上显示。
  4. 拖动应用悬浮窗口的边框,改变窗口尺寸,触发应用刷新,即可查看应用在不同窗口下的显示效果。
  5. 改变窗口尺寸的过程中,窗口尺寸可能超出屏幕尺寸。此时在屏幕中只能看到应用部分区域的显示,但可以通过移动窗口位置,查看应用其它区域的显示。
  6. 开发前请熟悉鸿蒙开发指导文档gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。

工程目录

AppMarket/entry/src/main/ets/
|---model
|   |---HomeData.ets                       // 主页用到的图片资源
|   |---HomeDataType.ets                   // 事件监听函数
|---pages                                  
|   |---index.ets                          // 首页
|---common                                    
|   |---BreakpointSystem.ets               // 媒体查询
|   |---Home.ets                           // 主容器
|   |---IndexApps.ets                      // app模块(包含安装,展示图片,更多功能)
|   |---IndexContent.ets                   // 内容模块
|   |---IndexEntrance.ets                  // 下一步模块(箭头跳转组件)
|   |---IndexHeader.ets                    // 头部组件
|   |---IndexSwiper.ets                    // 轮播图   
|   |---TabBarItem.ets                     // 导航栏

具体实现

本示例介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口,将页面分拆为5个部分。

底部/侧边导航栏

1、在sm和md断点下,导航栏在底部;在lg断点下,导航栏在左侧。
2、通过Tab组件的barPosition和vertical属性控制TabBar的位置在主轴方向起始或结尾位置和水平或垂直方向,同时还可以通过barWidth和barHeight属性控制TabBar的尺寸,[源码参考]。

/*

 * Copyright (c) 2022 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



import Home from '../common/Home'

import TabBarItem from '../common/TabBarItem'

import BreakpointSystem from '../common/BreakpointSystem'



@Entry

@Component

struct Index {

  @State currentIndex: number = 0

  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'

  private breakpointSystem: BreakpointSystem = new BreakpointSystem()

  private onTabChange = (index: number) = > {

    this.currentIndex = index

  }



  aboutToAppear() {

    this.breakpointSystem.register()

  }



  aboutToDisappear() {

    this.breakpointSystem.unregister()

  }



  @Builder

  tabItem(index: number, title: Resource, icon: Resource, iconSelected: Resource) {

    TabBarItem({

      index: index,

      currentIndex: this.currentIndex,

      title: title,

      icon: icon,

      iconSelected: iconSelected

    })

  }



  build() {

    Tabs({ barPosition: this.currentBreakpoint === 'lg' ? BarPosition.Start : BarPosition.End }) {

      TabContent() {

        Home()

      }

      .tabBar(this.tabItem(0, $r('app.string.tabBar1'), $r('app.media.ic_home_normal'), $r('app.media.ic_home_actived')))



      TabContent() {

      }

      .tabBar(this.tabItem(1, $r('app.string.tabBar2'), $r('app.media.ic_app_normal'), $r('app.media.ic_app_actived')))



      TabContent() {

      }

      .tabBar(this.tabItem(2, $r('app.string.tabBar3'), $r('app.media.ic_game_normal'), $r('app.media.ic_mine_actived')))



      TabContent() {

      }

      .tabBar(this.tabItem(3, $r('app.string.tabBar4'), $r('app.media.ic_search_normal'), $r('app.media.ic_search_actived')))



      TabContent() {

      }

      .tabBar(this.tabItem(4, $r('app.string.tabBar4'), $r('app.media.ic_mine_normal'), $r('app.media.ic_mine_actived')))

    }

    .barWidth(this.currentBreakpoint === 'lg' ? 96 : '100%')

    .barHeight(this.currentBreakpoint === 'lg' ? '60%' : 56)

    .vertical(this.currentBreakpoint === 'lg')

    .onChange(this.onTabChange)

    .backgroundColor('#F1F3F5')

  }

}

标题栏与搜索栏

通过栅格实现标题栏和搜索栏:在sm和md断点下分两行显示,在lg断点下单行显示,[源码参考]。

/*

 * Copyright (c) 2022 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



@Component

export default struct IndexHeader {

  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'



  @Builder searchBar() {

    Stack({alignContent: Alignment.End}) {

      TextInput({ placeholder: $r('app.string.search') })

        .placeholderColor('#FF000000')

        .placeholderFont({ size: 16, weight: 400 })

        .textAlign(TextAlign.Start)

        .caretColor('#FF000000')

        .width('100%')

        .height(40)

        .fontWeight(400)

        .padding({ top: 9, bottom: 9 })

        .fontSize(16)

        .backgroundColor(Color.White)



      Image($r('app.media.ic_public_search'))

        .width(16)

        .height(16)

        .margin({ right: 20 })

    }.height(56).width('100%')

  }



  @Builder titleBar() {

    Text($r('app.string.tabBar1'))

      .fontSize(24)

      .fontWeight(500)

      .fontColor('#18181A')

      .textAlign(TextAlign.Start)

      .height(56)

      .width('100%')

  }



  build() {

    GridRow() {

      GridCol({ span: { xs: 12, lg: 8 } }) {

        this.titleBar()

      }

      GridCol({ span: { xs: 12, lg: 4 } }) {

        this.searchBar()

      }

    }

    .width('100%')

    .height(this.currentBreakpoint === 'lg' ? 56 : 112)

    .padding({ left: 12, right: 12 })

  }

}

2、在sm和md断点下,标题栏和搜索栏占满12列,此时会自动换行显示。
3、在lg断点下,标题栏占8列而搜索栏占4列,此时标题栏和搜索栏在同一行中显示。

运营横幅

实现不同断点下的运营横幅:通过Swiper组件的displayCount属性,sm断点下显示一张图片,md断点下显示两张图片,lg断点下显示三张图片。

快捷入口

通过将justifyContent参数配置为FlexAlign.SpaceEvenly实现均分布局:在不同的断点下,快捷入口的5个图标始终均匀排布。

精品应用

通过List组件能力,实现延伸能力场景:随着可用显示区域的增加,精品应用中显示的图标数量也不断增加,[源码参考]。

/*

 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



import { AppItem, MyAppSource } from '../model/HomeDataType'



@Component

export default struct IndexApps {

  private title: Resource

  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md'

  private apps: AppItem[] = []



  @Builder

  appListHeader() {

    Row() {

      Text(this.title)

        .width(100)

        .fontSize(16)

        .textAlign(TextAlign.Start)

        .fontWeight(500)

      Blank()

      Text($r('app.string.more'))

        .fontSize(14)

        .textAlign(TextAlign.End)

        .fontWeight(400)

        .margin({ right: 2 })

      Image($r('app.media.ic_public_arrow_right'))

        .width(12)

        .height(18)

        .opacity(0.9)

        .objectFit(ImageFit.Fill)

    }

    .margin({ bottom: 9, top: 9 })

    .width('100%')

    .alignItems(VerticalAlign.Bottom)

  }



  @Builder

  appListItem(app:AppItem) {

    Column() {

      Image(app.image)

        .width(this.currentBreakpoint === 'lg' ? 80 : 56)

        .height(this.currentBreakpoint === 'lg' ? 80 : 56)

        .margin({ bottom: 8 })

      Text(app.title)

        .width(this.currentBreakpoint === 'lg' ? 80 : 56)

        .height(16)

        .fontSize(12)

        .textAlign(TextAlign.Center)

        .fontColor('#18181A')

        .margin({ bottom: 8 })

      Text($r('app.string.install'))

        .width(this.currentBreakpoint === 'lg' ? 80 : 56)

        .height(28)

        .fontColor('#0A59F7')

        .textAlign(TextAlign.Center)

        .borderRadius(this.currentBreakpoint === 'lg' ? 26 : 20)

        .fontWeight(500)

        .fontSize(12)

        .padding({ top: 6, bottom: 6, left: 8, right: 8 })

        .backgroundColor('rgba(0,0,0,0.05)')

    }

  }





  build() {

    Column() {

      this.appListHeader()

      List({ space: this.currentBreakpoint === 'lg' ? 44 : 20}) {

        LazyForEach(new MyAppSource(this.apps), app = > {

          ListItem() {

            this.appListItem(app)

          }

        }, app = > app.id)

      }

      .width('100%')

      .height(this.currentBreakpoint === 'lg' ? 140 : 120)

      .listDirection(Axis.Horizontal)

    }

    .width('100%')

    .height(this.currentBreakpoint === 'lg' ? 188 : 164)

    .padding({ bottom: 8, left: 12, right: 12 })

  }

}

`HarmonyOS与OpenHarmony鸿蒙文档籽料:mau123789是v直接拿`

鸿蒙

总体运行效果

通过将上述各页面在List() {}中引用组件后,可实现首页的组件整合渲染,即可完成整体页面开发。

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分