Flutter植物浇水提醒器:智能管理植物养护

项目简介

植物浇水提醒器是一款贴心的Flutter应用,帮助植物爱好者科学管理植物浇水。通过智能提醒功能,确保每株植物都能得到及时的水分补充,让养植物变得更加轻松。
运行效果图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

核心功能

  • 植物管理:添加、编辑、删除植物信息
  • 16种图标:丰富的植物图标选择
  • 6大分类:多肉、观叶、开花、水培等分类
  • 智能提醒:自动计算下次浇水时间
  • 一键浇水:快速记录浇水时间
  • 状态标识:颜色区分植物状态
  • Badge提醒:需要浇水的植物数量提醒
  • 数据持久化:本地保存所有记录

技术特点

  • Material Design 3设计风格
  • Emoji图标选择器
  • Slider滑块调节周期
  • 状态颜色区分(红/橙/绿)
  • Badge徽章提醒
  • 响应式卡片布局
  • SharedPreferences数据持久化

核心代码实现

1. 植物数据模型

class Plant {
  String id;
  String name;              // 植物名称
  String type;              // 植物类型
  int wateringInterval;     // 浇水周期(天)
  DateTime lastWatered;     // 上次浇水时间
  String location;          // 位置
  String notes;             // 备注
  String icon;              // 图标

  // 计算下次浇水日期
  DateTime get nextWateringDate {
    return lastWatered.add(Duration(days: wateringInterval));
  }

  // 判断是否需要浇水
  bool get needsWatering {
    return DateTime.now().isAfter(nextWateringDate);
  }

  // 距离下次浇水天数
  int get daysUntilWatering {
    return nextWateringDate.difference(DateTime.now()).inDays;
  }
}

模型字段说明

字段 类型 说明
id String 唯一标识符
name String 植物名称
type String 植物类型
wateringInterval int 浇水周期(天)
lastWatered DateTime 上次浇水时间
location String 摆放位置
notes String 养护备注
icon String Emoji图标

计算属性

  • nextWateringDate:下次浇水日期
  • needsWatering:是否需要浇水
  • daysUntilWatering:距离下次浇水天数

2. 状态判断与颜色

Color statusColor;
String statusText;
IconData statusIcon;

if (plant.needsWatering) {
  statusColor = Colors.red;
  statusText = '需要浇水';
  statusIcon = Icons.water_drop;
} else if (plant.daysUntilWatering <= 1) {
  statusColor = Colors.orange;
  statusText = '即将浇水';
  statusIcon = Icons.schedule;
} else {
  statusColor = Colors.green;
  statusText = '状态良好';
  statusIcon = Icons.check_circle;
}

状态级别

  • 🔴 需要浇水:已超过浇水时间
  • 🟠 即将浇水:1天内需要浇水
  • 🟢 状态良好:还有时间

3. Emoji图标选择器

final List<String> _icons = [
  '🌱', '🌿', '🌵', '🌴', '🌳', '🌲', '🌾',
  '🌺', '🌸', '🌼', '🌻', '🌷', '🌹', '🪴', '🍀'
];

Widget _buildIconSelector() {
  return Wrap(
    spacing: 8,
    runSpacing: 8,
    children: _icons.map((icon) {
      return InkWell(
        onTap: () {
          setState(() {
            _icon = icon;
          });
        },
        child: Container(
          width: 50,
          height: 50,
          decoration: BoxDecoration(
            color: _icon == icon
                ? Colors.green.withValues(alpha: 0.2)
                : Colors.grey.withValues(alpha: 0.1),
            borderRadius: BorderRadius.circular(8),
            border: Border.all(
              color: _icon == icon ? Colors.green : Colors.transparent,
              width: 2,
            ),
          ),
          child: Center(
            child: Text(icon, style: const TextStyle(fontSize: 28)),
          ),
        ),
      );
    }).toList(),
  );
}

4. Slider滑块调节周期

Card(
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Column(
      children: [
        const Text('浇水周期(天)'),
        Row(
          children: [
            IconButton(
              icon: const Icon(Icons.remove_circle_outline),
              onPressed: () {
                setState(() {
                  _wateringInterval = (_wateringInterval - 1).clamp(1, 30);
                });
              },
            ),
            Expanded(
              child: Slider(
                value: _wateringInterval.toDouble(),
                min: 1,
                max: 30,
                divisions: 29,
                label: '$_wateringInterval天',
                onChanged: (value) {
                  setState(() {
                    _wateringInterval = value.toInt();
                  });
                },
              ),
            ),
            IconButton(
              icon: const Icon(Icons.add_circle_outline),
              onPressed: () {
                setState(() {
                  _wateringInterval = (_wateringInterval + 1).clamp(1, 30);
                });
              },
            ),
          ],
        ),
        Text(
          '每 $_wateringInterval 天浇一次水',
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Colors.blue,
          ),
        ),
      ],
    ),
  ),
)

Slider参数说明

  • value:当前值
  • min:最小值(1天)
  • max:最大值(30天)
  • divisions:分段数(29段)
  • label:显示标签
  • onChanged:值变化回调

5. 一键浇水功能

void _waterPlant(Plant plant) {
  setState(() {
    plant.lastWatered = DateTime.now();  // 更新浇水时间
  });
  _savePlants();  // 保存数据
  
  // 显示提示
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text('已为《${plant.name}》浇水'),
      backgroundColor: Colors.green,
    ),
  );
}

// UI按钮
OutlinedButton.icon(
  onPressed: () => _waterPlant(plant),
  icon: const Icon(Icons.water_drop),
  label: const Text('浇水'),
  style: OutlinedButton.styleFrom(
    foregroundColor: Colors.blue,
  ),
)

6. Badge徽章提醒

// 获取需要浇水的植物
List<Plant> get _needsWateringPlants {
  return _plants.where((p) => p.needsWatering).toList();
}

// 显示Badge
final needsWateringCount = _needsWateringPlants.length;
if (needsWateringCount > 0)
  IconButton(
    icon: Badge(
      label: Text('$needsWateringCount'),
      child: const Icon(Icons.water_drop),
    ),
    onPressed: _showWateringReminders,
  ),

7. 浇水提醒对话框

void _showWateringReminders() {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('浇水提醒'),
      content: SingleChildScrollView(
        child: Column(
          children: [
            const Text('以下植物需要浇水:'),
            ..._needsWateringPlants.map((plant) => Row(
              children: [
                Text(plant.icon),
                Expanded(child: Text(plant.name)),
                TextButton(
                  onPressed: () {
                    _waterPlant(plant);
                    Navigator.pop(context);
                  },
                  child: const Text('浇水'),
                ),
              ],
            )),
          ],
        ),
      ),
    ),
  );
}

技术要点详解

Slider组件

Slider是Material Design的滑块组件:

Slider(
  value: _currentValue,
  min: 0,
  max: 100,
  divisions: 10,        // 分段数
  label: '$_currentValue',  // 显示标签
  onChanged: (value) {
    setState(() {
      _currentValue = value;
    });
  },
)

常用属性

  • value:当前值(必需)
  • min:最小值
  • max:最大值
  • divisions:分段数(离散值)
  • label:拖动时显示的标签
  • activeColor:激活颜色
  • inactiveColor:未激活颜色

Wrap组件

Wrap是自动换行的布局组件:

Wrap(
  spacing: 8,        // 主轴间距
  runSpacing: 8,     // 交叉轴间距
  alignment: WrapAlignment.start,
  children: [
    Chip(label: Text('标签1')),
    Chip(label: Text('标签2')),
    Chip(label: Text('标签3')),
  ],
)

与Row的区别

  • Row:单行,超出会溢出
  • Wrap:自动换行,适合标签云

SnackBar提示

SnackBar是底部弹出提示:

ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: Text('操作成功'),
    duration: Duration(seconds: 2),
    backgroundColor: Colors.green,
    action: SnackBarAction(
      label: '撤销',
      onPressed: () {
        // 撤销操作
      },
    ),
  ),
);

DateTime计算

常用的日期时间计算:

// 加减时间
final tomorrow = DateTime.now().add(Duration(days: 1));
final yesterday = DateTime.now().subtract(Duration(days: 1));

// 计算时间差
final difference = date2.difference(date1);
final days = difference.inDays;
final hours = difference.inHours;

// 判断先后
if (date1.isAfter(date2)) { }
if (date1.isBefore(date2)) { }
if (date1.isAtSameMomentAs(date2)) { }

常见植物浇水周期

浇水周期参考表

植物类型 浇水周期 养护要点
多肉植物 7-14天 少浇水,避免积水
绿萝 3-5天 保持土壤湿润
仙人掌 14-30天 耐旱,少浇水
吊兰 3-5天 喜湿润环境
发财树 7-10天 不宜过湿
虎皮兰 7-14天 耐旱植物
芦荟 10-14天 少浇水
富贵竹 水培每周换水 保持水质清洁
君子兰 5-7天 见干见湿
常春藤 3-5天 喜湿润

浇水原则

  1. 见干见湿:等土壤表面干了再浇
  2. 浇则浇透:浇水要浇到底部有水流出
  3. 季节调整:夏季多浇,冬季少浇
  4. 观察植物:叶子发蔫说明缺水
  5. 避免积水:积水容易烂根

功能扩展建议

1. 浇水历史记录

记录每次浇水的详细信息:

class WateringRecord {
  String plantId;
  DateTime wateredTime;
  String notes;
}

class Plant {
  // ... 其他字段
  List<WateringRecord> wateringHistory;
}

// 显示历史
Widget _buildWateringHistory(Plant plant) {
  return ListView.builder(
    itemCount: plant.wateringHistory.length,
    itemBuilder: (context, index) {
      final record = plant.wateringHistory[index];
      return ListTile(
        leading: const Icon(Icons.water_drop),
        title: Text('${record.wateredTime.year}-${record.wateredTime.month}-${record.wateredTime.day}'),
        subtitle: Text(record.notes),
      );
    },
  );
}

2. 施肥提醒

添加施肥管理功能:

class Plant {
  // ... 其他字段
  int fertilizingInterval;  // 施肥周期
  DateTime lastFertilized;  // 上次施肥时间
  
  DateTime get nextFertilizingDate {
    return lastFertilized.add(Duration(days: fertilizingInterval));
  }
  
  bool get needsFertilizing {
    return DateTime.now().isAfter(nextFertilizingDate);
  }
}

// 施肥按钮
OutlinedButton.icon(
  onPressed: () => _fertilizePlant(plant),
  icon: const Icon(Icons.grass),
  label: const Text('施肥'),
)

3. 植物照片

添加植物照片功能:

import 'package:image_picker/image_picker.dart';

class Plant {
  // ... 其他字段
  String? photoPath;
}

Future<void> _takePhoto() async {
  final picker = ImagePicker();
  final pickedFile = await picker.pickImage(source: ImageSource.camera);
  if (pickedFile != null) {
    setState(() {
      _photoPath = pickedFile.path;
    });
  }
}

// 显示照片
if (plant.photoPath != null)
  Image.file(
    File(plant.photoPath!),
    width: 100,
    height: 100,
    fit: BoxFit.cover,
  )

4. 生长记录

记录植物生长情况:

class GrowthRecord {
  DateTime date;
  double height;      // 高度(cm)
  int leafCount;      // 叶片数
  String condition;   // 生长状况
  String photo;       // 照片路径
}

class Plant {
  // ... 其他字段
  List<GrowthRecord> growthRecords;
}

// 生长曲线图
import 'package:fl_chart/fl_chart.dart';

Widget _buildGrowthChart(Plant plant) {
  return LineChart(
    LineChartData(
      lineBarsData: [
        LineChartBarData(
          spots: plant.growthRecords
              .asMap()
              .entries
              .map((e) => FlSpot(
                    e.key.toDouble(),
                    e.value.height,
                  ))
              .toList(),
          isCurved: true,
          color: Colors.green,
        ),
      ],
    ),
  );
}

5. 天气关联

根据天气调整浇水提醒:

import 'package:weather/weather.dart';

class WeatherService {
  Future<Weather> getCurrentWeather() async {
    // 获取当前天气
  }
  
  int adjustWateringInterval(int baseInterval, Weather weather) {
    // 晴天:减少周期
    if (weather.weatherMain == 'Clear') {
      return (baseInterval * 0.8).toInt();
    }
    // 雨天:增加周期
    if (weather.weatherMain == 'Rain') {
      return (baseInterval * 1.2).toInt();
    }
    return baseInterval;
  }
}

6. 本地通知

定时推送浇水提醒:

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class NotificationService {
  final FlutterLocalNotificationsPlugin _notifications =
      FlutterLocalNotificationsPlugin();

  Future<void> scheduleWateringReminder(Plant plant) async {
    await _notifications.zonedSchedule(
      plant.id.hashCode,
      '浇水提醒',
      '${plant.name}需要浇水了',
      tz.TZDateTime.from(plant.nextWateringDate, tz.local),
      const NotificationDetails(
        android: AndroidNotificationDetails(
          'watering_channel',
          '浇水提醒',
          importance: Importance.high,
        ),
      ),
      uiLocalNotificationDateInterpretation:
          UILocalNotificationDateInterpretation.absoluteTime,
    );
  }
}

常见问题解答

Q1: 如何批量浇水?

A: 添加批量操作功能:

void _waterAllNeededPlants() {
  final needsWatering = _plants.where((p) => p.needsWatering).toList();
  
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('批量浇水'),
      content: Text('确定要为${needsWatering.length}株植物浇水吗?'),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('取消'),
        ),
        FilledButton(
          onPressed: () {
            setState(() {
              for (var plant in needsWatering) {
                plant.lastWatered = DateTime.now();
              }
            });
            _savePlants();
            Navigator.pop(context);
          },
          child: const Text('确定'),
        ),
      ],
    ),
  );
}

Q2: 如何设置不同季节的浇水周期?

A: 添加季节调整功能:

class Plant {
  // ... 其他字段
  int springInterval;   // 春季周期
  int summerInterval;   // 夏季周期
  int autumnInterval;   // 秋季周期
  int winterInterval;   // 冬季周期
  
  int get currentInterval {
    final month = DateTime.now().month;
    if (month >= 3 && month <= 5) return springInterval;
    if (month >= 6 && month <= 8) return summerInterval;
    if (month >= 9 && month <= 11) return autumnInterval;
    return winterInterval;
  }
}

Q3: 如何导出植物清单?

A: 实现数据导出功能:

import 'package:csv/csv.dart';
import 'package:path_provider/path_provider.dart';

Future<void> exportToCSV(List<Plant> plants) async {
  List<List<dynamic>> rows = [
    ['名称', '类型', '浇水周期', '上次浇水', '下次浇水', '位置']
  ];

  for (var plant in plants) {
    rows.add([
      plant.name,
      plant.type,
      '${plant.wateringInterval}天',
      '${plant.lastWatered.year}-${plant.lastWatered.month}-${plant.lastWatered.day}',
      '${plant.nextWateringDate.year}-${plant.nextWateringDate.month}-${plant.nextWateringDate.day}',
      plant.location,
    ]);
  }

  String csv = const ListToCsvConverter().convert(rows);
  
  final directory = await getApplicationDocumentsDirectory();
  final file = File('${directory.path}/plants.csv');
  await file.writeAsString(csv);
}

Q4: 如何添加植物百科?

A: 集成植物知识库:

class PlantEncyclopedia {
  String name;
  String description;
  String wateringTips;
  String lightRequirement;
  String temperatureRange;
  List<String> commonIssues;
}

final encyclopedia = {
  '绿萝': PlantEncyclopedia(
    name: '绿萝',
    description: '常见的室内观叶植物',
    wateringTips: '保持土壤湿润,3-5天浇一次水',
    lightRequirement: '散射光,避免直射',
    temperatureRange: '15-30℃',
    commonIssues: ['叶子发黄:浇水过多', '叶尖干枯:空气干燥'],
  ),
};

// 显示百科
void _showEncyclopedia(String plantName) {
  final info = encyclopedia[plantName];
  if (info != null) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(info.name),
        content: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('简介:${info.description}'),
              Text('浇水:${info.wateringTips}'),
              Text('光照:${info.lightRequirement}'),
              Text('温度:${info.temperatureRange}'),
            ],
          ),
        ),
      ),
    );
  }
}

项目总结

实现的功能

✅ 植物信息管理(增删改查)
✅ 16种Emoji图标选择
✅ 6大植物分类
✅ 智能浇水提醒
✅ 一键浇水记录
✅ 状态颜色标识
✅ Badge徽章提醒
✅ Slider周期调节
✅ 数据本地持久化

技术亮点

  1. Emoji图标:丰富的植物图标选择
  2. Slider滑块:直观的周期调节
  3. 智能提醒:自动计算浇水时间
  4. 一键浇水:快速记录操作
  5. 状态可视化:颜色区分植物状态
  6. Badge提醒:醒目的数量标识
  7. 数据持久化:完整的JSON序列化

应用场景

  • 🌱 家庭植物养护
  • 🏢 办公室绿植管理
  • 🌿 阳台花园管理
  • 🪴 多肉植物收藏
  • 🌺 花卉爱好者
  • 🌳 园艺工作者

植物浇水提醒器是一款实用的植物养护应用,通过智能提醒和便捷操作,让养植物变得更加轻松愉快,帮助每株植物都能茁壮成长。

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

Logo

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

更多推荐