欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1. 项目介绍

月相是地球上看到的月球表面被太阳照明部分的形状,它随着月球绕地球运行而变化。月相小组件是一个基于 Flutter 开发的应用,它能够显示当前日期的月相、月龄和照明度,并且支持用户选择不同的日期查看对应的月相。本文将详细介绍如何使用 Flutter 实现这个实用的月相显示应用。

1.1 项目目标

  • 实现一个显示月相的应用
  • 计算并显示月龄和照明度
  • 支持选择不同日期查看月相
  • 显示月相阶段的详细说明
  • 采用美观的界面设计,模拟夜空效果
  • 确保在不同平台上的一致性表现

1.2 技术栈

  • Flutter:跨平台 UI 框架
  • Dart:编程语言
  • StatefulWidget:用于管理应用状态
  • math:用于计算月相的数学算法
  • intl:用于格式化日期
  • Stack 和 Positioned:用于实现月相的视觉效果
  • LinearGradient:用于实现渐变背景

2. 核心功能设计

2.1 月相计算

  • 月相算法:基于 J2000 纪元的月球轨道参数计算月相
  • 月龄计算:计算月球从新月开始的天数
  • 照明度计算:计算月球表面被太阳照明的百分比
  • 月相阶段:根据月龄确定月相阶段(新月、娥眉月、上弦月、盈凸月、满月、亏凸月、下弦月、残月)

2.2 日期选择

  • 日期选择器:使用 showDatePicker 实现日期选择功能
  • 日期范围:支持选择 1900 年到 2100 年之间的日期
  • 日期格式:使用 yyyy年MM月dd日 格式显示日期

2.3 月相显示

  • 月球可视化:使用圆形容器和渐变背景模拟月球
  • 月相遮罩:根据月相阶段显示不同的遮罩,模拟月相的视觉效果
  • 阴影效果:添加阴影效果,增强月球的立体感

2.4 月相信息

  • 月相名称:显示当前月相的名称
  • 月龄:显示月球从新月开始的天数
  • 照明度:显示月球表面被太阳照明的百分比
  • 月相说明:显示当前月相阶段的详细说明

2.5 界面设计

  • 夜空背景:使用深蓝色渐变背景,模拟夜空效果
  • 响应式设计:适应不同屏幕尺寸
  • 简洁布局:布局清晰,信息一目了然
  • 视觉效果:使用阴影和渐变增强视觉效果

3. 技术架构

3.1 项目结构

lib/
└── main.dart          # 主应用文件,包含所有代码

3.2 组件结构

MoonPhaseApp
└── MoonPhaseScreen
    ├── State management (_selectedDate, _currentMoonPhase, _moonAge, _illumination)
    ├── Moon phase calculation (_calculateMoonPhase)
    ├── Date selection (_selectDate)
    ├── UI components
    │   ├── Date picker button
    │   ├── Moon visualization (_buildMoonPhaseMask)
    │   ├── Moon phase information
    │   └── Moon phase description
    └── Helper methods
        ├── _getMoonPhaseName
        └── _getMoonPhaseDescription

3.3 数据模型

  • 选中日期DateTime 类型,存储用户选择的日期
  • 当前月相MoonPhase 枚举类型,存储当前月相阶段
  • 月龄double 类型,存储月球从新月开始的天数
  • 照明度double 类型,存储月球表面被太阳照明的百分比

4. 关键代码解析

4.1 月相计算

void _calculateMoonPhase(DateTime date) {
  // 计算月相的核心算法
  // 基于J2000纪元的月球轨道参数
  final epoch = DateTime.utc(2000, 1, 6, 18, 14, 0); // 2000年1月6日是新月
  final daysSinceEpoch = date.difference(epoch).inDays + (date.hour + date.minute / 60 + date.second / 3600) / 24;
  final lunarCycle = 29.530588853; // 月球公转周期(天)
  
  _moonAge = daysSinceEpoch % lunarCycle;
  final phaseAngle = (2 * pi * _moonAge) / lunarCycle;
  
  // 计算月球照明百分比
  _illumination = (1 - cos(phaseAngle)) / 2;
  
  // 确定月相
  final phase = _moonAge / lunarCycle;
  if (phase < 0.0625) {
    _currentMoonPhase = MoonPhase.newMoon;
  } else if (phase < 0.25) {
    _currentMoonPhase = MoonPhase.waxingCrescent;
  } else if (phase < 0.3125) {
    _currentMoonPhase = MoonPhase.firstQuarter;
  } else if (phase < 0.5) {
    _currentMoonPhase = MoonPhase.waxingGibbous;
  } else if (phase < 0.5625) {
    _currentMoonPhase = MoonPhase.fullMoon;
  } else if (phase < 0.75) {
    _currentMoonPhase = MoonPhase.waningGibbous;
  } else if (phase < 0.8125) {
    _currentMoonPhase = MoonPhase.lastQuarter;
  } else {
    _currentMoonPhase = MoonPhase.waningCrescent;
  }
  
  setState(() {});
}

代码解析

  • _calculateMoonPhase 方法:计算月相的核心方法
  • 基于 2000 年 1 月 6 日(新月)作为纪元
  • 计算从纪元到选定日期的天数
  • 根据月球公转周期(29.530588853 天)计算月龄
  • 根据月龄计算月相阶段和照明度
  • 使用 setState 更新界面

4.2 日期选择

void _selectDate() async {
  final DateTime? picked = await showDatePicker(
    context: context,
    initialDate: _selectedDate,
    firstDate: DateTime(1900),
    lastDate: DateTime(2100),
  );
  if (picked != null && picked != _selectedDate) {
    setState(() {
      _selectedDate = picked;
      _calculateMoonPhase(_selectedDate);
    });
  }
}

代码解析

  • _selectDate 方法:打开日期选择器,让用户选择日期
  • 使用 showDatePicker 显示日期选择器
  • 日期范围设置为 1900 年到 2100 年
  • 选择日期后,更新 _selectedDate 并重新计算月相

4.3 月相显示

Widget _buildMoonPhaseMask() {
  switch (_currentMoonPhase) {
    case MoonPhase.newMoon:
      return Container(
        width: 200,
        height: 200,
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.blue.shade900,
        ),
      );
    case MoonPhase.waxingCrescent:
      return Positioned(
        right: 0,
        child: Container(
          width: 100,
          height: 200,
          decoration: BoxDecoration(
            color: Colors.blue.shade900,
            borderRadius: const BorderRadius.only(
              topRight: Radius.circular(100),
              bottomRight: Radius.circular(100),
            ),
          ),
        ),
      );
    case MoonPhase.firstQuarter:
      return Positioned(
        right: 0,
        child: Container(
          width: 100,
          height: 200,
          decoration: BoxDecoration(
            color: Colors.blue.shade900,
            borderRadius: const BorderRadius.only(
              topRight: Radius.circular(100),
              bottomRight: Radius.circular(100),
            ),
          ),
        ),
      );
    case MoonPhase.waxingGibbous:
      return Positioned(
        right: 0,
        child: Container(
          width: 50,
          height: 200,
          decoration: BoxDecoration(
            color: Colors.blue.shade900,
            borderRadius: const BorderRadius.only(
              topRight: Radius.circular(100),
              bottomRight: Radius.circular(100),
            ),
          ),
        ),
      );
    case MoonPhase.fullMoon:
      return Container();
    case MoonPhase.waningGibbous:
      return Positioned(

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐