0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙OS开发:【一次开发,多端部署】(一多天气)项目

jf_46214456 来源:jf_46214456 作者:jf_46214456 2024-05-20 14:59 次阅读

一多天气

介绍

本示例展示一个天气应用界面,包括首页、城市管理、添加城市、更新时间弹窗,体现一次开发,多端部署的能力。

1.本示例参考一次开发,多端部署的指导,主要使用响应式布局的栅格断点系统实现在不同尺寸窗口界面上不同的显示效果。

2.使用[SideBarContainer]实现侧边栏功能。

3.使用[栅格容器组件]实现界面内容的分割和展示。

4.使用Canvas和CanvasRenderingContext2D完成空气质量和日出月落图的曲线绘制。

开发前请熟悉鸿蒙开发指导文档 :[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]

效果预览

image.png

使用说明:

1.启动应用后,首页展示已添加城市的天气信息,默认展示2个城市,左右滑动可以切换城市,在LG设备上,默认显示侧边栏,侧边栏显示时,右侧内容区占2/3,侧边栏隐藏时,内容区自动铺满界面。

2.在支持窗口自由拖拽的设备上,拖拽窗口大小,可以分别实现拖动到最大窗口侧边栏显示(点击侧边栏控制按钮可以隐藏和显示侧边栏),拖动窗口缩小到MD大小时侧边栏和侧边栏控制按钮隐藏。

3.在支持窗口自由拖拽的设备上,拖拽窗口大小,天气内容区跟随窗口大小会自动换行显示。

4.点击右上角菜单按钮,在菜单中点击 更新时间 ,弹出更新时间弹窗,没有功能,此处只做展示,在平板设备上显示2列,在小屏设备上显示一列。

5.点击右上角菜单按钮,在菜单中点击 管理城市 ,进入管理城市界面,展示已添加的城市,在平板设备上显示2列,在小屏设备上显示一列。

6.点击管理城市界面的 添加城市 ,进入添加城市界面,已添加的城市不可点击,未添加的城市点击可以添加并返回管理城市界面显示。

工程目录

/code/SuperFeature/MultiDeviceAppDev/Weather/product/default
└─src
    ├─main
    │  │
    │  ├─ets
    │  │  ├─Application
    │  │  │      MyAbilityStage.ts          //自定义ability
    │  │  │
    │  │  ├─common                          //公共资源库
    │  │  ├─feature
    │  │  │      AirQualityFeature.ts       //空气绘画
    │  │  │      SunCanvasFeature.ts        //晴天绘画
    │  │  │
    │  │  ├─MainAbility
    │  │  │      MainAbility.ts             //主窗口
    │  │  │
    │  │  └─pages
    │  │      │  AddCity.ets                //添加城市
    │  │      │  CityList.ets               //城市列表
    │  │      │  Home.ets                   //入口
    │  │      │
    │  │      └─home
    │  │              AirQuality.ets         //空气质量
    │  │              HomeContent.ets        //主页面
    │  │              HoursWeather.ets       //每小时天气组件
    │  │              IndexEnd.ets           //首页尾 
    │  │              IndexHeader.ets        //首页头
    │  │              IndexTitleBar.ets      //首页标题
    │  │              LifeIndex.ets          //生活建议
    │  │              MultidayWeather.ets    //天气组件
    │  │              SideContent.ets        //侧边栏
    │  │              SunCanvas.ets          //晴天样式
    │  │              UpdateTimeDialog.ets   //时间更新弹窗
    │  │
    │  └─resources                           //资源包

具体实现

1、home.ets中引入SideContent()和homeContent()。
2、定义showSideBar来判断是否展示侧边栏,定义mediaquery.MediaQueryListener媒体监听器smListener、mdListener、lgListener。
3、在aboutToAppear调用mediaquery对界面进行监听,[源码参考]。

/*

 * 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 mediaquery from '@ohos.mediaquery';

import HomeContent from './home/HomeContent';

import IndexTitleBar from './home/IndexTitleBar';

import SideContent from './home/SideContent';

import { CityListData, Style, getBg, getCityListWeatherData, Logger } from '@ohos/common';



const TAG: string = 'Home';



@Entry

@Component

struct Home {

  @StorageLink('isRefresh') @Watch('refreshChange') isRefresh: boolean = false;

  @StorageLink('swiperIndex') swiperIndex: number = 0;

  @State curBp: string = 'md';

  @State cityListWeatherData: CityListData[] = getCityListWeatherData();

  @State popupState: boolean = false;

  @State showSideBar: boolean = false;

  private smListener: mediaquery.MediaQueryListener;

  private mdListener: mediaquery.MediaQueryListener;

  private lgListener: mediaquery.MediaQueryListener;



  build() {

    SideBarContainer(SideBarContainerType.Embed) {

      SideContent({ showSideBar: $showSideBar })

        .height('100%')

      Column() {

        IndexTitleBar({ showSideBar: $showSideBar })

          .height(56)

        Swiper() {

          ForEach(this.cityListWeatherData, (item, index) = > {

            HomeContent({ showSideBar: this.showSideBar, cityListData: item, index: index })

          }, item = > item.city)

        }

        .id('swiper')

        .padding({ left: Style.NORMAL_PADDING, right: Style.NORMAL_PADDING })

        .indicatorStyle({

          selectedColor: Color.White

        })

        .onChange(index = > {

          this.swiperIndex = index;

          AppStorage.SetOrCreate('swiperIndex', this.swiperIndex);

        })

        .indicator(this.curBp !== 'lg')

        .index(this.swiperIndex)

        .loop(false)

        .width('100%')

        .layoutWeight(1)

      }

      .height('100%')

    }

    .height('100%')

    .sideBarWidth('33.3%')

    .minSideBarWidth('33.3%')

    .maxSideBarWidth('33.3%')

    .showControlButton(false)

    .showSideBar(this.showSideBar)

    .backgroundImageSize(ImageSize.Cover)

    .backgroundImage(getBg(this.cityListWeatherData[this.swiperIndex].header.weatherType))

  }



  aboutToAppear() {

    this.smListener = mediaquery.matchMediaSync('(320vp< width<=600vp)');

    this.smListener.on("change", this.isBreakpointSM);

    this.mdListener = mediaquery.matchMediaSync('(600vp< width<=840vp)');

    this.mdListener.on("change", this.isBreakpointMD);

    this.lgListener = mediaquery.matchMediaSync('(840vp< width)');

    this.lgListener.on("change", this.isBreakpointLG);

  }



  aboutToDisappear() {

    this.smListener.off("change", this.isBreakpointSM);

    this.mdListener.off("change", this.isBreakpointMD);

    this.lgListener.off("change", this.isBreakpointLG);

  }



  isBreakpointSM = (mediaQueryResult) = > {

    if (mediaQueryResult.matches) {

      this.curBp = 'sm';

      this.showSideBar = false;

      AppStorage.SetOrCreate('curBp', this.curBp);

    }

    Logger.info(TAG, `this.curBp = ${this.curBp}`);

  }

  isBreakpointMD = (mediaQueryResult) = > {

    if (mediaQueryResult.matches) {

      this.curBp = 'md';

      this.showSideBar = false;

      AppStorage.SetOrCreate('curBp', this.curBp);

    }

    Logger.info(TAG, `this.curBp = ${this.curBp}`);

  }

  isBreakpointLG = (mediaQueryResult) = > {

    if (mediaQueryResult.matches) {

      if (this.curBp !== 'lg') {

        this.showSideBar = true;

      }

      this.curBp = 'lg';

      AppStorage.SetOrCreate('curBp', this.curBp);

    }

    Logger.info(TAG, `this.curBp = ${this.curBp}`);

  }



  refreshChange() {

    Logger.info(TAG, `refreshChange}`);

    if (this.isRefresh) {

      this.cityListWeatherData = getCityListWeatherData();

      AppStorage.SetOrCreate('isRefresh', false);

    }

    Logger.info(TAG, `refreshChange, this.cityListWeatherData.length = ${this.cityListWeatherData.length}`);

  }

}

`HarmonyOSOpenHarmony鸿蒙文档籽料:mau123789是v直接拿`

搜狗高速浏览器截图20240326151450.png

4、监听到当前屏幕大小,调用this.isBreakpoint断点,对curBp、showSideBar进行赋值,[源码参考]。

/*

 * 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 mediaquery from '@ohos.mediaquery';

import HomeContent from './home/HomeContent';

import IndexTitleBar from './home/IndexTitleBar';

import SideContent from './home/SideContent';

import { CityListData, Style, getBg, getCityListWeatherData, Logger } from '@ohos/common';



const TAG: string = 'Home';



@Entry

@Component

struct Home {

  @StorageLink('isRefresh') @Watch('refreshChange') isRefresh: boolean = false;

  @StorageLink('swiperIndex') swiperIndex: number = 0;

  @State curBp: string = 'md';

  @State cityListWeatherData: CityListData[] = getCityListWeatherData();

  @State popupState: boolean = false;

  @State showSideBar: boolean = false;

  private smListener: mediaquery.MediaQueryListener;

  private mdListener: mediaquery.MediaQueryListener;

  private lgListener: mediaquery.MediaQueryListener;



  build() {

    SideBarContainer(SideBarContainerType.Embed) {

      SideContent({ showSideBar: $showSideBar })

        .height('100%')

      Column() {

        IndexTitleBar({ showSideBar: $showSideBar })

          .height(56)

        Swiper() {

          ForEach(this.cityListWeatherData, (item, index) = > {

            HomeContent({ showSideBar: this.showSideBar, cityListData: item, index: index })

          }, item = > item.city)

        }

        .id('swiper')

        .padding({ left: Style.NORMAL_PADDING, right: Style.NORMAL_PADDING })

        .indicatorStyle({

          selectedColor: Color.White

        })

        .onChange(index = > {

          this.swiperIndex = index;

          AppStorage.SetOrCreate('swiperIndex', this.swiperIndex);

        })

        .indicator(this.curBp !== 'lg')

        .index(this.swiperIndex)

        .loop(false)

        .width('100%')

        .layoutWeight(1)

      }

      .height('100%')

    }

    .height('100%')

    .sideBarWidth('33.3%')

    .minSideBarWidth('33.3%')

    .maxSideBarWidth('33.3%')

    .showControlButton(false)

    .showSideBar(this.showSideBar)

    .backgroundImageSize(ImageSize.Cover)

    .backgroundImage(getBg(this.cityListWeatherData[this.swiperIndex].header.weatherType))

  }



  aboutToAppear() {

    this.smListener = mediaquery.matchMediaSync('(320vp< width<=600vp)');

    this.smListener.on("change", this.isBreakpointSM);

    this.mdListener = mediaquery.matchMediaSync('(600vp< width<=840vp)');

    this.mdListener.on("change", this.isBreakpointMD);

    this.lgListener = mediaquery.matchMediaSync('(840vp< width)');

    this.lgListener.on("change", this.isBreakpointLG);

  }



  aboutToDisappear() {

    this.smListener.off("change", this.isBreakpointSM);

    this.mdListener.off("change", this.isBreakpointMD);

    this.lgListener.off("change", this.isBreakpointLG);

  }



  isBreakpointSM = (mediaQueryResult) = > {

    if (mediaQueryResult.matches) {

      this.curBp = 'sm';

      this.showSideBar = false;

      AppStorage.SetOrCreate('curBp', this.curBp);

    }

    Logger.info(TAG, `this.curBp = ${this.curBp}`);

  }

  isBreakpointMD = (mediaQueryResult) = > {

    if (mediaQueryResult.matches) {

      this.curBp = 'md';

      this.showSideBar = false;

      AppStorage.SetOrCreate('curBp', this.curBp);

    }

    Logger.info(TAG, `this.curBp = ${this.curBp}`);

  }

  isBreakpointLG = (mediaQueryResult) = > {

    if (mediaQueryResult.matches) {

      if (this.curBp !== 'lg') {

        this.showSideBar = true;

      }

      this.curBp = 'lg';

      AppStorage.SetOrCreate('curBp', this.curBp);

    }

    Logger.info(TAG, `this.curBp = ${this.curBp}`);

  }



  refreshChange() {

    Logger.info(TAG, `refreshChange}`);

    if (this.isRefresh) {

      this.cityListWeatherData = getCityListWeatherData();

      AppStorage.SetOrCreate('isRefresh', false);

    }

    Logger.info(TAG, `refreshChange, this.cityListWeatherData.length = ${this.cityListWeatherData.length}`);

  }

}

审核编辑 黄宇

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

    关注

    0

    文章

    13

    浏览量

    11242
  • 鸿蒙
    +关注

    关注

    57

    文章

    2345

    浏览量

    42822
  • 鸿蒙OS
    +关注

    关注

    0

    文章

    188

    浏览量

    4383
收藏 人收藏

    评论

    相关推荐

    ​HarmonyOS"一次开发多端部署"优秀实践——玩机技巧

    的潜在用户群体。个应用要在多类设备上提供统的内容,需要适配不同的屏幕尺寸和硬件,开发成本较高。"一次开发
    的头像 发表于 08-30 10:25 2807次阅读
    ​HarmonyOS"<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>"优秀实践——玩机技巧

    HarmonyOS开发案例:【一次开发多端部署(视频应用)】

    者提供了“一次开发多端部署”的系统能力,让开发者可以基于一次
    的头像 发表于 05-11 15:41 1442次阅读
    HarmonyOS<b class='flag-5'>开发</b>案例:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>(视频应用)】

    HarmonyOS开发案例:【一次开发多端部署-音乐专辑】

    基于自适应和响应式布局,实现一次开发多端部署音乐专辑页面。
    的头像 发表于 05-13 16:48 679次阅读
    HarmonyOS<b class='flag-5'>开发</b>案例:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>-音乐专辑】

    鸿蒙OS开发:【一次开发多端部署】(天气应用)案例

    本章通过天气应用,介绍一多应用的整体开发过程,包括UX设计、工程管理及调试、页面开发等。
    的头像 发表于 05-15 15:42 1039次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】(<b class='flag-5'>天气</b>应用)案例

    鸿蒙OS开发:【一次开发多端部署】(音乐专辑主页)

    本示例使用一次开发多端部署中介绍的自适应布局能力和响应式布局能力进行多设备(或多窗口尺寸)适配,保证应用在不同设备或不同窗口尺寸下可以正常显示。
    的头像 发表于 05-21 14:48 733次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】(音乐专辑主页)

    鸿蒙OS开发:【一次开发多端部署】(音乐专辑页面)

    基于自适应和响应式布局,实现一次开发多端部署音乐专辑页面。
    的头像 发表于 05-25 16:21 790次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】(音乐专辑页面)

    鸿蒙OS开发:【一次开发多端部署】(视频应用)

    者提供了“一次开发多端部署”的系统能力,让开发者可以基于一次
    的头像 发表于 05-25 16:29 4535次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】(视频应用)

    鸿蒙OS开发:典型页面场景【一次开发多端部署】实战(音乐专辑页2)

    本示例使用[一次开发多端部署]中介绍的自适应布局能力和响应式布局能力进行多设备(或多窗口尺寸)适配,保证应用在不同设备或不同窗口尺寸下可以正常显示。
    的头像 发表于 05-25 16:47 2096次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:典型页面场景【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】实战(音乐专辑页2)

    鸿蒙OS开发:典型页面场景【一次开发多端部署】实战(设置典型页面)

    本示例展示了设置应用的典型页面,其在小窗口和大窗口有不同的显示效果,体现一次开发多端部署的能力。
    的头像 发表于 05-27 09:36 1141次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:典型页面场景【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】实战(设置典型页面)

    HarmonyOS\"一次开发多端部署\"优秀实践——玩机技巧,码上起航

    的潜在用户群体。个应用要在多类设备上提供统的内容,需要适配不同的屏幕尺寸和硬件,开发成本较高。\"一次开发
    发表于 08-30 18:14

    华为开发者大会2021:一次开发 多端部署

    一次开发 多端部署使能开发者从单设备生态跨入多设备生态!
    的头像 发表于 10-22 15:09 1642次阅读
    华为<b class='flag-5'>开发</b>者大会2021:<b class='flag-5'>一次</b><b class='flag-5'>开发</b> <b class='flag-5'>多端</b><b class='flag-5'>部署</b>

    华为开发者大会2021:软件部总裁龚体 鸿蒙系统 一次开发 多端部署 万物互连

    华为开发者大会2021:鸿蒙系统 一次开发 多端部署 万物互连 在华为
    的头像 发表于 10-22 15:09 4546次阅读
    华为<b class='flag-5'>开发</b>者大会2021:软件部总裁龚体 <b class='flag-5'>鸿蒙</b>系统 <b class='flag-5'>一次</b><b class='flag-5'>开发</b> <b class='flag-5'>多端</b><b class='flag-5'>部署</b> 万物互连

    鸿蒙OS开发:【一次开发多端部署】(简介)

    随着终端设备形态日益多样化,分布式威廉希尔官方网站 逐渐打破单硬件边界,个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大
    的头像 发表于 05-14 15:20 1203次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】(简介)

    鸿蒙OS开发:【一次开发多端部署】(多设备自适应能力)简单介绍

    本示例是《一次开发多端部署》的配套示例代码,展示了[页面开发一多能力],包括自适应布局、响应
    的头像 发表于 05-21 14:59 2407次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】(多设备自适应能力)简单介绍

    鸿蒙OS开发:【一次开发多端部署】( 设置app页面)

    本示例展示了设置应用的典型页面,其在小窗口和大窗口有不同的显示效果,体现一次开发多端部署的能力。
    的头像 发表于 05-21 14:56 1049次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>OS</b><b class='flag-5'>开发</b>:【<b class='flag-5'>一次</b><b class='flag-5'>开发</b>,<b class='flag-5'>多端</b><b class='flag-5'>部署</b>】( 设置app页面)