作者: Luna

  • Flutter自定义主题Theme最佳实践

    Flutter自定义主题Theme最佳实践

    Flutter中使用主题,基本都是通过ThemeData来进行的(不会有人用CupertinoThemeData吧,如果有,我敬你是个汉子)。而ThemeData的编写和定义,都牢牢的和Material Design风格绑定在了一起。
    那么,问题来了,我们在开发过程中,设计师给出的设计稿,通常带有设计师自己的一套风格主题。
    这些风格主题和被强绑定的Material Design风格,基本都是天差地别,没有一丝丝的相似。

    这就出现了一些解决方案,不过基本都是自定义一个AppColors之类的类,然后通过状态管理框架(例如:Getx、Bloc、Provider等等)进行全局刷新。
    这里就出现了一些纠结的地方:

    • Flutter中默认的Theme已经提供了切换的方法,无需再通过状态管理框架再写一次了,但是强制使用了Material Design风格,基本上和设计师给的冲突了。
    • 通过状态管理框架自己实现一套颜色配置,完全抛弃Theme提供的所有帮助。

    其实,我们可以通过ThemeExtension来进行扩展,把我们的theme进行扩展。
    来,上教程!

    1. 先来一个AppColors压压惊

    当然,无论怎样,都需要定义我们的AppColors。在这里,用来存放所有的设计师给的规范颜色值。
    例如:

    import 'package:flutter/material.dart';
    
    /// app_colors.dart
    
    class AppLightColors {
      static const Color demo1 = Colors.red; // 红色的
      static const Color demo2 = Colors.green; // 绿色的
      // ... 这里接着写设计师提供的所有颜色值
    }
    
    class AppDarkColors {
      static const Color demo1 = Colors.black; // 黑色的
      static const Color demo2 = Colors.white; // 白色的
      // ... 这里接着写设计师提供的所有颜色值
    }
    

    2. 定义我们自己的Theme

    接着,我们就要创建我们自己的Theme了,通过ThemeExtension来实现,这里有几点需要注意:

    • 如果颜色值很多(基本都会很多),尽量使用ai来帮你实现复制粘贴内容,这里的颜色值需要完完整整的都定义出来,跟着设计师给出的颜色表。
    • lerp方法是一个渐变方法,切换主题后,所有颜色会有一个渐变效果,很好看。可以直接使用Color.lerp方法进行。
      例如:
    import 'package:flutter/material.dart';
    
    /// app_colors_extension.dart
    
    class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
      AppColorsExtension({
        required this.demo1,
        required this.demo2,
        // ... 这里需要定义所有的值,如果写的累就找AI吧
      });
    
      final Color demo1; // 演示值1
      final Color demo2; // 演示值2
      // ... 这里需要定义所有的值,如果写的累就找AI吧
    
      @override
      ThemeExtension<AppColorsExtension> copyWith({Color? demo1, Color? demo2}) {
        return AppColorsExtension(
          demo1: demo1 ?? this.demo1,
          demo2: demo2 ?? this.demo2,
          // ... 这里需要定义所有的值,如果写的累就找AI吧
        );
      }
    
      @override
      ThemeExtension<AppColorsExtension> lerp(
        ThemeExtension<AppColorsExtension>? other,
        double t,
      ) {
        // 这里排除了不是我们自定义的情况
        if (other is! AppColorsExtension) {
          return this;
        }
    
        return AppColorsExtension(
          demo1: Color.lerp(demo1, other.demo1, t)!,
          demo2: Color.lerp(demo2, other.demo2, t)!,
          // ... 这里需要定义所有的值,如果写的累就找AI吧
        );
      }
    }
    

    3. 写我们的Theme吧

    前两步,我们定义好了ThemeExtension和Color,现在,通过自定义的theme,我们把ThemeExtension和Color绑定在一起。
    例如:

    import 'package:flutter/material.dart';
    
    import 'app_colors.dart';
    import 'app_colors_extension.dart';
    
    /// app_themes.dart
    
    // 我们自定义的亮色主题
    class LightTheme {
      static ThemeData theme = ThemeData.light().copyWith(
        extensions: [_lightAppColors],
      );
    
      static final _lightAppColors = AppColorsExtension(
        demo1: AppLightColors.demo1,
        demo2: AppLightColors.demo2,
      );
    }
    
    // 我们自定义的暗色主题
    class DarkTheme {
      static ThemeData theme = ThemeData.dark().copyWith(
        extensions: [_darkAppColors],
      );
    
      static final _darkAppColors = AppColorsExtension(
        demo1: AppDarkColors.demo1,
        demo2: AppDarkColors.demo2,
      );
    }
    

    4. 把自定的Theme配置到MaterialApp中

    上一步中我们写好了亮色主题和暗色主题,那么我们把这个主题绑定到Flutter的项目中。
    例如:

    import 'package:flutter/material.dart';
    
    import 'home_page.dart';
    import 'app_themes.dart';
    
    /// main.dart
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatefulWidget {
      const MyApp({super.key});
    
      @override
      State<MyApp> createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      ThemeMode _themeMode = ThemeMode.light; // 默认设置为light
    
      // 这里定义一个切换主题的方法,提供给HomePage使用,这里看大家的状态管理框架要怎么处理了
      void toggleTheme() {
        setState(() {
          _themeMode = _themeMode == ThemeMode.light
              ? ThemeMode.dark
              : ThemeMode.light;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Theme Demo',
          theme: AppLightTheme.theme, // 这里定义亮色主题
          darkTheme: AppDarkTheme.theme, // 这里定义暗色主题
          themeMode: _themeMode, // 设置主题模式,这里就要看大家的状态管理框架要怎么处理了
          home: HomePage(toggleTheme: toggleTheme),
        );
      }
    }
    
    

    5. 用起来用起来

    至此,我们所有的配置工作就全部做完了,现在,就开始用起来。
    获取颜色的方法:Theme.of(context).extension<AppColorsExtension>()?.demo1
    例如:

    import 'package:flutter/material.dart';
    
    import 'app_colors_extension.dart';
    
    /// home_page.dart
    
    class HomePage extends StatelessWidget {
      const HomePage({super.key, required this.toggleTheme});
    
      final void Function() toggleTheme;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text('Flutter Theme Demo')),
          body: Center(
            child: Column(
              mainAxisAlignment: .center,
              children: [
                Container(
                  decoration: BoxDecoration(
                    color: Theme.of(
                      context,
                    ).extension<AppColorsExtension>()!.demo1, // 这里就是使用我们自定义的颜色
                    border: Border.all(width: 1, color: Colors.grey),
                  ),
                  height: 120,
                  width: 120,
                ),
                Container(
                  decoration: BoxDecoration(
                    color: Theme.of(
                      context,
                    ).extension<AppColorsExtension>()?.demo2, // 这里就是使用我们自定义的颜色
                    border: Border.all(width: 1, color: Colors.grey),
                  ),
                  height: 120,
                  width: 120,
                ),
                ElevatedButton(
                  onPressed: () {
                    // 点击这里切换主题, 从light切换到dark, 从dark切换到light
                    toggleTheme();
                  },
                  child: Text("切换主题"),
                ),
              ],
            ),
          ),
        );
      }
    }
    

    这样,我们的代码就都写好啦。

    6. 来看看效果

    这就是效果咯,来看一下,感受一下

    浅色深色动画效果

    7. 一点点简化的小方法

    我们看到,第5步中,获取颜色的方法Theme.of(context).extension<AppColorsExtension>()?.demo1,写起来有点长,我们来化简一下:
    例如:
    首先,得修改一下app_themes.dart文件,来提供默认的颜色

    // ......
    // 我们自定义的亮色主题
    class AppLightTheme {
      static ThemeData theme = ThemeData.light().copyWith(
        extensions: [lightAppColors], // <-- 改了这里,把下划线去掉,变为public字段
      );
    
      // 改了这里,把下划线去掉,变为public字段
      static final lightAppColors = AppColorsExtension(
        demo1: AppLightColors.demo1,
        demo2: AppLightColors.demo2,
      );
    }
    // ......
    

    然后,我们新增一个Extension类,来简化颜色的调用:

    import 'package:flutter/material.dart';
    
    import 'app_colors_extension.dart';
    import 'app_themes.dart';
    
    /// theme_extension.dart
    
    extension AppThemeExtension on ThemeData {
      /// 用法: Theme.of(context).appColors;
      AppColorsExtension get appColors =>
          extension<AppColorsExtension>() ?? AppLightTheme.lightAppColors;
    }
    

    这时,我们调用的时候,可以使用Theme.of(context).appColors.demo1来进行。
    例如:

    import 'package:flutter/material.dart';
    
    import 'theme_extension.dart'; // 这里就需要引入这个类来使用我们的简化方法
    // import 'app_colors_extension.dart';   <-- 这个就不用啦
    
    /// home_page.dart
    
    class HomePage extends StatelessWidget {
      const HomePage({super.key, required this.toggleTheme});
    
      final void Function() toggleTheme;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text('Flutter Theme Demo')),
          body: Center(
            child: Column(
              mainAxisAlignment: .center,
              children: [
                Container(
                  decoration: BoxDecoration(
                    color: Theme.of(context).appColors.demo1, // 这里就是使用我们自定义的颜色
                    border: Border.all(width: 1, color: Colors.grey),
                  ),
                  height: 120,
                  width: 120,
                ),
                Container(
                  decoration: BoxDecoration(
                    color: Theme.of(context).appColors.demo2, // 这里就是使用我们自定义的颜色
                    border: Border.all(width: 1, color: Colors.grey),
                  ),
                  height: 120,
                  width: 120,
                ),
                ElevatedButton(
                  onPressed: () {
                    // 点击这里切换主题, 从light切换到dark, 从dark切换到light
                    toggleTheme();
                  },
                  child: Text("切换主题"),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    

    8. 结束

    至此,主题配置就完成了。祝大家玩得开心。

  • 还是习惯了用Qoder

    还是习惯了用Qoder

    Qoder 贵是贵了点,但的确是好用呀。

    来一个我的推广链接:点我去购买

  • iOS发布的Screenshots

    iOS发布的Screenshots

    • iPhone 6.5 -> iPhone 13 Pro Max / iPhone 14 Plus
    • iPhone 5.5 -> iPhone 8 Plus
    • iPad Pro (3rd Gen) 12.9 -> iPad Pro (12.9-inch)
    • iPad Pro (2nd Gen) 12.9 -> iPad Pro (12.9-inch)

    https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications

    加密需要添加

    Info.plist

    <key>ITSAppUsesNonExemptEncryption</key>
    <false/>

  • 颠覆认知!当代养生秘籍:放下沙拉碗,端起烤肉盘

    颠覆认知!当代养生秘籍:放下沙拉碗,端起烤肉盘

    最近我发现一个惊人的养生真相:那些整天捧着蔬菜沙拉、鲜榨果汁的养生达人可能正走在慢性自杀的道路上!根据我在烧烤摊潜心研究三年的观察报告显示,真正长寿的秘诀藏在滋滋作响的肥牛片和翻滚的红油火锅里。

    一、人类进化史早已给出答案
    考古学家在周口店遗址发现,北京猿人平均每天摄入4.7公斤肉类。国际营养学期刊《Meat Science》最新研究指出,人类大脑容量与烤肉摄入量呈正相关。我的蒙古族朋友巴特尔就是活例证,他家祖祖辈辈以牛羊肉为主食,85岁的爷爷现在还能骑马摔跤,而隔壁天天啃胡萝卜的王大爷,去年就因为骨质疏松坐上了轮椅。

    二、烧烤是最佳营养转化器
    中山路烧烤店老板老张跟踪记录了10年顾客健康状况:每周吃三次烧烤的人,感冒频率降低63%。科学解释是明火高温能彻底分解肉类中的有害物质,同时产生丰富的芳香烃化合物——这可是激活多巴胺的天然催化剂。还记得上个月部门团建吗?吃了20串羊肉的小李第二天提案通过率100%,而只吃烤茄子的组长至今还在改第七稿。

    三、火锅汤底的养生玄学
    某医科大学最新论文显示,持续沸腾2小时以上的牛油锅底,会产生类似灵芝多糖的活性物质。上周我带素食主义的闺蜜去吃九宫格,三天后她惊喜地发现生理期不痛了,脸上的痘印都淡了两个色号。现在她每天带着便携火锅底料上班,说是要”内服外敷双管齐下”。

    警惕这些隐形杀手:

    1. 蔬菜:现代农业残留的38种农药中,有27种会在绿叶菜表面形成结晶。更可怕的是,西蓝花含有天然硫苷毒素,其毒性堪比微量砒霜。
    2. 水果:某品牌果汁检测报告显示,500ml橙汁=15块方糖+200种防腐剂。我同事每天喝”健康果昔”,三个月胖了18斤,体检时医生看着他的脂肪肝直摇头。

    真实案例:
    程序员阿凯坚持三年”全素养生”,结果体检报告出现12项异常。在我的劝说下开始执行”烤肉康复计划”,早烤肉夹馍午韩式烤牛肠晚潮汕牛肉锅,三个月后尿酸值神奇回落,发际线都前移了0.5厘米!现在他办公桌下常备迷你烤炉,说是要”把失去的胶原蛋白吃回来”。

  • 什么是家电行业中的“白电”和“黑电”

    什么是家电行业中的“白电”和“黑电”

    白电

    白电即白色家电,通常指可以替代人们家务劳动、改善生活环境提高物质生活水平的电器产品。以下是关于白电的详细介绍:

    名称由来

    早期,冰箱、洗衣机、空调等这类电器产品的外观大多以白色为主,因此被统称为白电抖音百科。

    产品特点

    • 功能实用性:主要用于减轻人们的家务劳动强度和改善生活环境,如洗衣机可自动清洗衣物,节省人力和时间;冰箱能长时间保存食物,保持其新鲜度;空调可调节室内温度和湿度,创造舒适的居住环境抖音百科。
    • 工作原理:更多地是通过电机将电能转换为热能、动能进行工作,如洗衣机的电机带动洗衣桶旋转实现洗涤功能,冰箱的压缩机电机工作实现制冷循环抖音百科。

    主要类型

    • 制冷电器:如电冰箱、冰柜等,通过制冷系统降低温度,使食物在低温环境下得以长时间保存,延长其保质期。
    • 清洁电器:包括洗衣机、洗碗机、吸尘器等,帮助人们清洗衣物、餐具和清洁家居环境,提高清洁效率,减轻家务负担。
    • 厨卫电器:部分厨房电器如微波炉、烤箱、电烤箱、油烟机等属于白电范畴,可帮助人们烹饪食物、处理食材和排除厨房油烟。此外,还有热水器,为人们提供生活热水,满足洗澡、洗碗等日常用水需求。
    • 空气调节电器:主要是空调,包括家用空调、中央空调等,可调节室内的温度、湿度、风速等参数,使室内环境保持舒适。

    黑电

    黑电是黑色家电(Black – colored Household Electric Appliances)的简称。

    1. 名称起源
      • 最初,像电视机、录像机等这类家电外壳多为黑色,与白电相对应,所以被称为黑电。不过,现在黑电产品的外观颜色多种多样,已经不局限于黑色。
    2. 主要功能特点
      • 信息娱乐功能为主:黑电主要用于提供视听娱乐和信息传播服务。例如,电视机是典型的黑电产品,它能够接收并播放各种电视节目,包括新闻、电视剧、电影、体育赛事等多种内容,让用户获取信息和享受视听娱乐。
      • 信号处理与显示技术核心:黑电产品的核心技术通常涉及信号的接收、处理和显示。以智能电视为例,它需要接收来自电视台、网络流媒体等多种渠道的信号,通过内部的芯片和软件进行解码、处理,然后在屏幕上清晰地显示出图像和播放声音。
    3. 主要产品类型
      • 传统显示设备
        • 电视机:从早期的黑白电视机,到彩色显像管电视机,再到如今的液晶电视(LCD)、有机发光二极管电视(OLED)等。例如,液晶电视通过液晶显示技术,利用液晶分子的排列变化来控制光的透过和遮挡,从而显示出不同的图像;而 OLED 电视则具有自发光、对比度高、视角广等优点。
        • 显示器:主要用于连接电脑等设备,作为信息显示终端。包括普通的办公显示器和用于游戏、设计等专业领域的高分辨率、高刷新率显示器。
      • 家庭影院设备
        • 投影仪:可以将图像投射到屏幕或墙壁上,提供大屏幕的视觉体验。有传统的灯泡投影仪,其亮度较高,适合在光线较复杂的环境使用;还有新型的激光投影仪,色彩表现更好,使用寿命更长。
        • 音响设备:如家庭影院音响系统,包括前置音箱、后置音箱、中置音箱和低音炮等,通过多个声道的配合,营造出环绕立体声效果,增强音频的沉浸感,提升用户在观看电影、听音乐等场景下的听觉体验。
      • 视频播放设备
        • 机顶盒:用于接收和处理数字电视信号,有的机顶盒还能连接网络,提供网络电视、视频点播等功能。例如,网络机顶盒可以安装各种应用程序,用户能够通过它观看优酷、腾讯视频等平台上的海量视频内容。
        • 蓝光播放器:主要用于播放蓝光光盘,蓝光光盘具有高容量、高清晰度的特点,能够提供高质量的视频和音频播放效果,让用户欣赏到高清电影、音乐会等内容。
  • 不要再吃草莓!

    不要再吃草莓!

    草莓在种植和食用过程中确实存在一些潜在的健康风险。以下是关于吃草莓及其种植过程中可能对人体产生的危害的详细分析:

    1. 农药残留的危害

    草莓在种植过程中容易受到病虫害的侵袭,因此农民通常会喷洒大量农药来保护作物。这些农药可能包括杀虫剂、杀菌剂和除草剂等。如果草莓在采摘前没有经过充分的清洗或处理,农药残留可能对人体健康造成以下危害:

    • 急性中毒:高剂量的农药残留可能导致恶心、呕吐、头痛甚至更严重的中毒症状。
    • 慢性健康问题:长期摄入低剂量的农药残留可能增加患癌症、神经系统疾病和内分泌紊乱的风险。
    • 儿童和孕妇的敏感性:儿童和孕妇对农药残留更为敏感,可能影响胎儿发育或儿童的神经系统发育。

    2. 添加剂和保鲜剂的使用

    为了延长草莓的保质期和改善外观,一些种植者或经销商可能会使用化学添加剂或保鲜剂。这些化学物质可能包括:

    • 防腐剂:如二氧化硫等,可能引发过敏反应,尤其是对哮喘患者。
    • 染色剂:某些不法商贩可能使用非法染色剂使草莓颜色更鲜艳,这些化学物质可能对肝脏和肾脏造成负担。

    3. 草莓本身的潜在危害

    • 过敏反应:草莓是常见的过敏原之一,部分人群食用后可能出现皮肤瘙痒、口腔肿胀、呼吸困难等过敏症状。
    • 草酸含量:草莓中含有一定量的草酸,过量摄入可能增加肾结石的风险,尤其是对于已经有肾脏问题的人群。
    • 消化不适:草莓中的纤维和果酸可能刺激胃肠道,导致腹胀、腹泻或胃酸过多。

    4. 环境污染的影响

    草莓种植过程中使用的农药和化肥可能对土壤和水源造成污染,进而影响周边生态系统和人类健康:

    • 土壤退化:长期使用化学肥料和农药可能导致土壤肥力下降,甚至污染地下水。
    • 水源污染:农药和化肥可能通过雨水冲刷进入河流和湖泊,影响饮用水安全。

    5. 人工种植的潜在问题

    • 激素使用:为了加速草莓的生长和增加产量,部分种植者可能使用植物激素,这些化学物质可能对人体内分泌系统产生干扰。
    • 温室种植的隐患:温室种植的草莓可能因通风不良而滋生霉菌,霉菌产生的毒素对人体健康有害。

    总结

    草莓其种植和食用过程中存在的农药残留、添加剂使用、环境污染等问题可能对人体健康产生负面影响。