从零开始纯血鸿蒙天气预报-主界面(1)

易得天气

开始做天气预报主界面,目前完成了天气预报的头部UI。

等天气预报完成后会将代码进行开源

效果图

天气预报数据源

kotlin 复制代码
// 生成天气背景
this.weatherBg = WeatherDataUtils.generateWeatherBg(weatherData)
// 根据天气背景计算天气头部是否是dark模式
this.isWeatherHeaderDark = WeatherDataUtils.isWeatherHeaderDark(this.weatherBg)
// 根据天气背景计算天气内容是否是dark模式
this.isDark = WeatherDataUtils.isDark(this.weatherBg)
// 根据天气背景计算天气面板的透明度
this.panelOpacity = WeatherDataUtils.calPanelOpacity(this.weatherBg)
// 生成天气items数据
this.weatherItems = WeatherDataUtils.generateWeatherItems(AppRuntimeData.getInstance().currentWeatherCardSort,
  AppRuntimeData.getInstance().currentWeatherObservesCardSort, weatherData)

页面布局

scss 复制代码
Stack({ alignContent: Alignment.Top }) {
  List({ scroller: this.weatherMainVM.listScroller }) {
    ForEach(this.weatherMainVM.weatherItemsFilter, (item: WeatherItemData) => {
      ListItem() {
        Text(item.itemType.toString())
          .width("100%")
          .height(800)
          .fontSize(20)
          .textAlign(TextAlign.Center)
          .backgroundColor(Color.Gray)
      }
    }, (item: WeatherItemData) => item.itemType.toString())
  }
  .width('100%')
  .height('100%')
  .sticky(StickyStyle.Header)
  .scrollBar(BarState.Off)
  .edgeEffect(EdgeEffect.Spring, { alwaysEnabled: true })
  .margin({ top: px2vp(AppUtil.getStatusBarHeight()) + Constants.WEATHER_HEADER_MIN_HEIGHT })
  .contentStartOffset(Constants.WEATHER_HEADER_MAX_HEIGHT - Constants.WEATHER_HEADER_MIN_HEIGHT)
  .onDidScroll(() => {
    const yOffset = this.weatherMainVM.listScroller.currentOffset().yOffset
    this.weatherMainVM.setWeatherHeaderOffset(yOffset + (Constants.WEATHER_HEADER_MAX_HEIGHT - Constants.WEATHER_HEADER_MIN_HEIGHT))
  })

  WeatherHeaderWidget({
    isWeatherHeaderDark: this.weatherMainVM.isWeatherHeaderDark,
    weatherItemData: this.weatherMainVM.weatherHeaderItemData,
    weatherHeaderOffset: this.weatherMainVM.weatherHeaderOffset
  })
}

监听weatherHeaderOffset变化从而改变页面高度以及透明度

ini 复制代码
@Monitor('weatherHeaderOffset')
onOffsetChanged(monitor: IMonitor) {
  const offset = monitor.value<number>()?.now ?? 0
  const percent = fixPercent(offset / (Constants.WEATHER_HEADER_MAX_HEIGHT - Constants.WEATHER_HEADER_MIN_HEIGHT))
  const currentHeight = Constants.WEATHER_HEADER_MAX_HEIGHT - offset;
  const minHeight = Constants.WEATHER_HEADER_MIN_HEIGHT
  this.currentHeight = currentHeight < minHeight ? minHeight : currentHeight

  const marginTop = this.minMarginTop + (this.maxMarginTop - this.minMarginTop) * (1 - percent)
  this.marginTop = marginTop < this.minMarginTop ? this.minMarginTop : marginTop

  const opacity1 = 1 - (percent - 0.2) / (0.3 - 0.2)
  this.opacity1 = opacity1 > 1 ? 1 : (opacity1 < 0 ? 0 : opacity1)
  const opacity2 = 1 - (percent - 0.4) / (0.5 - 0.4)
  this.opacity2 = opacity2 > 1 ? 1 : (opacity2 < 0 ? 0 : opacity2)
  const opacity3 = 1 - (percent - 0.7) / (0.8 - 0.7)
  this.opacity3 = opacity3 > 1 ? 1 : (opacity3 < 0 ? 0 : opacity3)
  const opacity4 = 1 - (percent - 0.9) / (0.9 - 1.0)
  this.opacity4 = opacity4 > 1 ? 1 : (opacity4 < 0 ? 0 : opacity4)
}

item布局

scss 复制代码
build() {
  Column() {
    Text(this.title)
      .textStyle(28, FontWeight.Normal, this.isWeatherHeaderDark)
      .margin({ top: this.marginTop })
    Stack({ alignContent: Alignment.Top }) {
      Column({ space: 5 }) {
        Row() {
          Blank()
            .layoutWeight(1)
          Text(this.temp)
            .textStyle(92, FontWeight.Lighter, this.isWeatherHeaderDark)
          Text('°')
            .textStyle(86, FontWeight.Lighter, this.isWeatherHeaderDark)
            .layoutWeight(1)
        }
        .width('100%')
        .opacity(this.opacity3)

        Row() {
          Text('最\n高')
            .textStyle(15, FontWeight.Normal, this.isWeatherHeaderDark)
          Blank().width(3)
          Text(getTemp(this.currentWeatherDetailData?.high))
            .textStyle(34, FontWeight.Lighter, this.isWeatherHeaderDark)
          Blank().width(12)
          Text('最\n低')
            .textStyle(15, FontWeight.Normal, this.isWeatherHeaderDark)
          Blank().width(3)
          Text(getTemp(this.currentWeatherDetailData?.low))
            .textStyle(34, FontWeight.Lighter, this.isWeatherHeaderDark)
        }
        .opacity(this.opacity2)

        Text(this.weatherDesc)
          .textStyle(20, FontWeight.Normal, this.isWeatherHeaderDark)
          .opacity(this.opacity1)
      }

      Text(`${getTemp(this.weatherItemData?.weatherData?.observe?.temp)} | ${this.weatherDesc}`)
        .textStyle(20, FontWeight.Normal, this.isWeatherHeaderDark)
        .opacity(this.opacity4)
    }
    .margin({ top: 5 })
  }
  .width('100%')
  .height(this.currentHeight)
  .margin({ top: px2vp(AppUtil.getStatusBarHeight()) })
  .hitTestBehavior(HitTestMode.Transparent)
  .clip(true)
}
相关推荐
加农炮手Jinx11 小时前
Flutter 组件 ubuntu_service 适配鸿蒙 HarmonyOS 实战:底层系统服务治理,构建鸿蒙 Linux 子系统与守护进程交互架构
flutter·harmonyos·鸿蒙·openharmony·ubuntu_service
里欧跑得慢11 小时前
Flutter 三方库 mobx_codegen — 自动化驱动的高性能响应式状态管理(适配鸿蒙 HarmonyOS Next ohos)
flutter·自动化·harmonyos
王码码203511 小时前
Flutter 三方库 login_client 的鸿蒙化适配指南 - 打造工业级安全登录、OAuth2 自动化鉴权、鸿蒙级身份守门员
flutter·harmonyos·鸿蒙·openharmony·login_client
星辰徐哥11 小时前
鸿蒙金融理财全栈项目——上线与运维、用户反馈、持续迭代
运维·金融·harmonyos
加农炮手Jinx11 小时前
Flutter 三方库 cloudflare 鸿蒙云边协同分发流适配精讲:直连全球高速存储网关阵列无缝吞吐海量动静态画像资源,构筑大吞吐业务级网络负载安全分流-适配鸿蒙 HarmonyOS ohos
网络·flutter·harmonyos
大雷神15 小时前
HarmonyOS APP<玩转React>开源教程十一:组件化开发概述
前端·react.js·harmonyos
国医中兴18 小时前
Flutter 三方库 dson 的鸿蒙化适配指南 - 极简的序列化魔法、在鸿蒙端实现反射式 JSON 映射实战
flutter·harmonyos·鸿蒙·openharmony
池央20 小时前
在鸿蒙上跑 AI Agent:JiuwenClaw-on-OpenHarmony 完整实战
人工智能·华为·harmonyos
互联网散修20 小时前
零基础鸿蒙应用开发第五节:基础数据类型与对象类型转换
华为·harmonyos·鸿蒙应用开发入门教程
弓.长.20 小时前
ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-fast-image — 高性能图片加载组件
react native·react.js·harmonyos