flutter ThemeData的使用 屏幕适配方案rpx px

本篇文章转自我自己的有道云笔记 想看图片去那里

文档:Day 3_30 单独补充 Theme ?..
链接:http://note.youdao.com/noteshare?id=81a13195fe536af098cc1207a67265d6&sub=BDEE12E5CCA74B0396AEA3B040B28D03

小项目练习

解决一个问题

Q: 为什么 initStatus里面的modalRoute 只能在delayed或者 timer才能使用

A: 因为在我们的initStatus还没有准备好

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-merTmcPo-1588730587955)(5FD28E2F954844BF95F0E1E64EA43374)]

所以我们的这个东西没有办法完成

它这里需要通过 这个context来一层一层的找

这个时候context还没有准备好 这些Widget Element还没有放到map里面

这个时候我们通过这个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F5puWPiq-1588730587957)(D9EBBBC98AB541A8848630DFAF65B584)]

方法来找是不能找到的

我们是找不到的

但是这个时候我们可以用一个Timer.run 来完成对应的操作

Timer.run是一个异步操作它不会阻塞当前线程的

但是这个run它的作用就是将这个 callback 里面的东西加入到事件队列后面

所以它会挨个事件队列进行处理

这个时候它就会在准备好了之后 就可以在里面拿到 这个context了

当然并不是所有的东西都可以通过这个东西拿到

小项目练习

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qXHoTJDR-1588730587958)(4B5D64C0141E4DC290A180079E1C6E23)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DOWno3Fw-1588730587960)(8701EBDEBDE04286A09AE25C8A502299)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ugqxjzyy-1588730587962)(5A1E710DBB6B47BCBB0168ABC7E0E517)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OphGSntq-1588730587965)(C0BAEB16360848018E042B12EC6DE1A4)]

可以查看一下这个东西是怎么制作的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R42G7j33-1588730587966)(D08018C475594681B5306377890B73DF)]

这个收藏因该是在多个界面进行一个共享的

同时可以在主页的收藏中进行查看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jOpMPqax-1588730587969)(37E68ADFE85C4110ACA38D732D1C320D)]

这样我们就可以使用状态管理了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RqVR0qYG-1588730587971)(0215D1D3F9204840A346BF0730282D8D)]

这个东西 flutter直接默认就帮我们提供了

这里一旦选择了 过滤 那我们之后在选择商品的时候 就会过滤信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uKOFHWS0-1588730587973)(E6AD045A95C8475F96EE32C6DC80F7C1)]

一旦选中这些信息 后面再展示的时候 后面就会过滤这些东西

学习目的

  • 虽然它的这个比较简单 但是我们可以通过这个东西 我们可以吧之前的东西串联起来
  • 还要讲一下 屏幕适配的问题
  • 文件结构 组件化的开发思想 如何组织 如何划分

我们这里因该就是选用的rpx的方案来解决屏幕适配

我们通过这个简单的案例 我们还可以补充一些其他的东西

我们的flutter最主要就是开发移动端 可能后面会开发web 或者pc但是现在还处于 实验版本

appid/ 应用名称 图标 启动图

单独补充

主题风格

主题 最主要是对项目 中的统一的风格做一个规范

每次我们在建一个新的文件的 时候这个MaterialApp里面就有一个参数 theme: ThemeData()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CT7JZCia-1588730587975)(AE760C32D67C4955BA317542D4D47A46)]

一旦你设置了这个Theme 我们项目里面的某些东西就会根据你设置的东西来进行显示

比如我们这里讲这个primarySwatich: 设置为蓝色 那我们的很多的地方它都是蓝色的

主题样式的作用

  • 设置了主题以后, 某些Widget就会自动使用主题的样式
  • 将某些样式放到主题中进行统一管理, 在应用程序的其他地方直接进行引用

如果我们在样式中定义了 样式 那我们就可以在其他的widget里面直接引用这个 通过我们的Theme.of(context) 来取对应的样式 这个东西的原理就是一个InheritedWidget

这样我们就可以在上面同意管理这个样式

使用Theme

Theme分为全局的Theme 和 局部的Theme

全局的Theme 我们一旦设置就会影响我们整个项目的 样式

那我们就新建一个文件

我们之前有一个地方一直没有讲

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6oELuYi4-1588730587977)(B2E42A2CF0FD4B71A6CF1C93CC1ABF97)]

但是这个MaterialApp上面都还有一个title但是这个title是在哪里显示的

我们退出去看到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T8oi0Je7-1588730587980)(C718F19269174236870C867F909DC4CA)]

这里显示的是learn_flutter 项目名

回到桌面以后这个app也叫做 learn_flutter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Yzjj7nP-1588730587982)(E48288A75F644E2EAC3B3DCA48635F7A)]

它也不是这个名字 所以这个title它到底是放在哪里的?

但是注意这个flutter它的sdk也是一个很大的东西 它就和IOS SDK Android SDK 一样是一个很大的东西

这个SDK 就是一个大的体系 所以如果自己下来遇到这些问题我们可以去自己查阅文档

那这个title到底是干什么的呢

所以我们来试着查一下文档

我们来到这个api.flutter.dev

api.flutter.dev

然后来到搜索搜索这个MaterialApp这个东西

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IgARckh6-1588730587985)(77F709C342DC4534A5732FC8CE96416A)]

然后我们要看属性就往下翻

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1s5vX7tK-1588730587987)(A4243FBCA93842D1B4C0A67B6F6E1090)]

然后看到title 它这个属性的顺序是一个 a,b,c,d的排序

然后我们点进去

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vI0nJI2K-1588730587989)(1BFE3859E96A4EAF8F33AD2CEBEF35DA)]

它这里title出现在应用程序管理的快照上面

但是它并不是所有 有些android是不能这样查看的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RvD6G59P-1588730587991)(F420FF7623DE4E89BDB6B57702421A82)]

这个就是一个快照 在最近使用的app 查看 地方就能显示这个title这个东西是在android

但是ios里面是不能使用这个属性的

它说这个东西是在info.plist里面使用的

这个地方我们还是要讲 Theme只不过我们这里是要讲怎么查文档

flutter.dev/docs

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yc1oaxr0-1588730587993)(E5C446CD30D145CFA0D876554E058519)]

这个是看文档

api.flutter.dev 查类

  • 方法怎么用
  • 属性怎么用

Theme的使用

  1. 一旦设置了主题, 那么应用程序里面的某些Widget就会直接使用主题的样式

首先是 ThemeData的 brightness: 属性

  • brightness属性
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light
      ),
      home: HYHomeScreen(),
    );
  }
}

它默认就是light所以这里是不会有变化的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrsWqBTP-1588730588001)(06269779484B425EB2107C15232EBDD4)]

但是如果改成dark 那就是暗黑模式

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.dark
      ),
      home: HYHomeScreen(),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1InNROYj-1588730588003)(15C23D97F6B44217B545CB53805C3904)]

但是我们一般不会去自己改这个属性

因该是去 设置里面直接改这个 让它变成暗黑模式而不是在设置的时候让它变成暗黑模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WgGakmDe-1588730588005)(F7408ED013CC4997942AF72F6BE287D1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6N0krs0a-1588730588007)(E11863345DD9422BAADD27592DC66C65)]

这里可以打开暗黑模式

ios是在开发这中打开暗黑模式 都差不多就不演示了

所以这里 就要根据系统是不是暗黑模式写出两套样式

这个东西我们后面再说这个东西

所以这个东西一般情况下都是light

第二个属性

  • primarySwatch属性

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WtWQ97kJ-1588730588009)(201F10D08CD44DA897E2A9706A78AB4A)]

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light,
//        2. 主要样式
        primarySwatch: Colors.pink
      ),
      home: HYHomeScreen(),
    );
  }
}

这个primary的意思就是主要的 它就是主要样式的决定者

可以看到它把 nav栏的背景设置成了粉色

floatActionButton也设置成粉色了

同时这个底部的导航栏也有这个 颜色的变化

还有就是我们搞一个 Switch这个就是一个checkBox一样的东西

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Column(
          children: [
            Text("hello world"),
            Switch(value: true, onChanged: (value) {
              
            },)
          ],
        )
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            title: Text("首页"),
            icon: Icon(Icons.people)
          ),
          BottomNavigationBarItem(
              title: Text("分类"),
              icon: Icon(Icons.people)
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {

        },
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xELqU5zB-1588730588011)(A53359E4C346481EAEFF3460855E0180)]

可以看到这个按钮的颜色也是粉色的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-At5O9MgO-1588730588013)(DC2F194E4B73425F825F29B644ADD200)]

还有就是这个东西它是一个浅蓝

这个东西它是一个浅蓝 那么这个东西是怎么来的呢

官方没有对这个颜色做一个总结 那 我们怎么知道 这些东西的颜色

  • 自己做总结
  • StackOverFlow 上面有一个官方人员 上回答问题 这个primiarySwitch 什么地方也没有回答的特别详细 只是说 导航栏 floatActionButton 然后还有等等 这个tabbar都是 试出来的

我们改一个地方 我们的所有地方都会改变颜色

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KeZtF9El-1588730588018)(A5D6E920C0A940BA895A05E715822E0D)]

还有一个问题就是我们的这个开关和ios的开关 长的不一样

如果你想用ios的开关的话我们可以用这个 CupertinoSwitch 来让这个开关长的和ios的开关一样

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Column(
          children: [
            Text("hello world"),
            Switch(value: true, onChanged: (value) {

            },),
            CupertinoSwitch(value: true, onChanged: (value) {

            },)
          ],
        )
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            title: Text("首页"),
            icon: Icon(Icons.people)
          ),
          BottomNavigationBarItem(
              title: Text("分类"),
              icon: Icon(Icons.people)
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {

        },
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XkOqT3l0-1588730588021)(681D07FCF9D54160A419E876B58DA0A2)]

但是这个开关它的这里的颜色就始终是绿色了

但是这个颜色只是不依赖这个primarySwatch 但是还是可以修改的

我们使用activeColor来进行修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mU1JLG8s-1588730588022)(EED4CAC24983498DB2D1919C0F220B92)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9j5E088-1588730588025)(8903DCDCFE1A4AEA919394908CE1A00F)]

当然这里还有一个细节

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vm7oaowU-1588730588027)(1B6DA686D1424736B988332E54DD145C)]

这个颜色它也是使用的主题的颜色 但是它使用的是一个比较浅的颜色 那它是怎么根据我们的比较浅颜色来做这个东西的呢

我们创建的颜色的方式有很多

 Colors.red
 Color(0xffbbaacc)
 Color.formRGBA(255,255,255,255 )

那这里我们创建主题颜色的时候primarySwatch 是直接使用的Colors.red

那我们这里就是因为Colors.red创建出来它不是一个单纯的纯色 它内部是有很多的颜色的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rspkBXNu-1588730588029)(C174F9BCC120410290DC358FE018A617)]

而通过我们之前看到的重载的运算符 可以通过[] 来取出里面的每个值

这里也是这样 它不能是一个单纯的纯色

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5HxFEQl-1588730588033)(D69D8CA2462D4A9DAD93823655AA139A)]

它这里就直接报错了

它这里primarySwatch 这里要传入的就不是一个普通的Color 它让我们传入的是一个MaterialColor

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-teTZnBUs-1588730588036)(227AC9E34D39487A82222B738700AE8B)]

你会返现它让我们传入的是这样的一个东西

因为父类的引用不能指向子类的对象

  MaterialColor color = Color(0xff000000);
//  父类的指针不能 指向子类的对象

当然这个MaterialColor不是直接继承至Color

向我们之前使用的Colors.red 这个东西它是 MterialColor 所以可以直接填在 primarySwatch 上面

我们可以用这个

这里我们就可以用一个父类的指针指向一个子类的对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jzm4TJJs-1588730588041)(DEED53E2CC3B4DD4A3A0489926EA5EFD)]

这个MaterialColor就是这样的一个MaterialColor 这个东西就是一个map

所以我们可以通过这样的方式来取出这个值

我们默认都是使用的这个值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RGMEGpXX-1588730588045)(6B7AF4B486C446C889E46BD65864AFC0)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BjOZ2KPy-1588730588048)(E3374787DC3143638C3365A965409CED)]

可以看到这个primaryColor在这里被使用了

最终

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Frgzo7h-1588730588050)(C05D83E4EF284DA9A035492B00482737)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tq4bvwTD-1588730588055)(35603AB25CDC4963B3AB87F46CDF2252)]

这个就最后传给了这个Color的构造器

如果你想要浅一点的颜色

我们可以Color color = Colors.red[100]

它会通过这个东西取出这个值

这个东西它 能这样使用这个[] 并不是因为它是一个数组

这个东西它是一个类 但是它 使用了运算符的重载

所以我们可以对这个对象来使用这个方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsNPerzy-1588730588058)(A10C96ACF09C4E35A9CB247792B4E8E7)]

但是注意 Colors.xx对于一些颜色是没有这个MaterialColor的属性的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ilNQ0Kl-1588730588059)(F558BC24C02543029DABAA6302D879DA)]

所以并不是所有的这个Colors都这样做

所以这里 primarySwatch 使用了 Colors.red

它就会从MaterialColor 中取出不同的颜色来使用

虽然黑白没有这个MaterialColor 但是我们可以通过这种方式来 取出不同的颜色

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cIF8vaGj-1588730588062)(6E83E7268B9F42CCB7F0BDA8010D169D)]

  • primaryColor 属性

而是 primarySwatch 包含了primaryColor和accentColor

primaryColor 这个东西主要是导航和tabBar的颜色

然后如果设置了 primaryColor就会覆盖掉以前设置的颜色

      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light,
//        2. 主要样式
        primarySwatch: Colors.red,
//        3. primaryColor: 导航栏和tabBar的颜色
        primaryColor: Colors.green,
      ),

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7cXzjnJB-1588730588065)(942A3DB896F1451A8CC66DB5C2443C0E)]

  • accentColor

这个东西就可以单独设置一下 floatActionButton 和 Switch这些东西的样式

可以看到 这个颜色

      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light,
//        2. 主要样式
        primarySwatch: Colors.red,
//        3. primaryColor: 导航栏和tabBar的颜色
        primaryColor: Colors.green,
//        4. accentColor 这个东西相当于是单独设置floatActionButton这种东西
        accentColor: Colors.blue
      ),

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AQ1Zx9XC-1588730588070)(30253A9385B64C5098FF3C08F1312434)]

所以这个其实是以结合

然后你可以看到这个源码里面有很多的

  factory ThemeData({
    Brightness brightness,
    MaterialColor primarySwatch,
    Color primaryColor,
    Brightness primaryColorBrightness,
    Color primaryColorLight,
    Color primaryColorDark,
    Color accentColor,
    Brightness accentColorBrightness,
    Color canvasColor,
    Color scaffoldBackgroundColor,
    Color bottomAppBarColor,
    Color cardColor,
    Color dividerColor,
    Color focusColor,
    Color hoverColor,
    Color highlightColor,
    Color splashColor,
    InteractiveInkFeatureFactory splashFactory,
    Color selectedRowColor,
    Color unselectedWidgetColor,
    Color disabledColor,
    Color buttonColor,
    ButtonThemeData buttonTheme,
    ToggleButtonsThemeData toggleButtonsTheme,
    Color secondaryHeaderColor,
    Color textSelectionColor,
    Color cursorColor,
    Color textSelectionHandleColor,
    Color backgroundColor,
    Color dialogBackgroundColor,
    Color indicatorColor,
    Color hintColor,
    Color errorColor,
    Color toggleableActiveColor,
    String fontFamily,
    TextTheme textTheme,
    TextTheme primaryTextTheme,
    TextTheme accentTextTheme,
    InputDecorationTheme inputDecorationTheme,
    IconThemeData iconTheme,
    IconThemeData primaryIconTheme,
    IconThemeData accentIconTheme,
    SliderThemeData sliderTheme,
    TabBarTheme tabBarTheme,
    TooltipThemeData tooltipTheme,
    CardTheme cardTheme,
    ChipThemeData chipTheme,
    TargetPlatform platform,
    MaterialTapTargetSize materialTapTargetSize,
    bool applyElevationOverlayColor,
    PageTransitionsTheme pageTransitionsTheme,
    AppBarTheme appBarTheme,
    BottomAppBarTheme bottomAppBarTheme,
    ColorScheme colorScheme,
    DialogTheme dialogTheme,
    FloatingActionButtonThemeData floatingActionButtonTheme,
    Typography typography,
    CupertinoThemeData cupertinoOverrideTheme,
    SnackBarThemeData snackBarTheme,
    BottomSheetThemeData bottomSheetTheme,
    PopupMenuThemeData popupMenuTheme,
    MaterialBannerThemeData bannerTheme,
    DividerThemeData dividerTheme,
    ButtonBarThemeData buttonBarTheme,
  })
  • 它还可以设置某些Widget的样式
      Center(
        child: Column(
          children: [
            Text("hello world"),
            Switch(value: true, onChanged: (value) {

            },),
            CupertinoSwitch(value: true, onChanged: (value) {

            }, activeColor: Colors.red,),
            RaisedButton(
              child: Text("点击"),
              onPressed: () {

              },
            )
          ],
        )
      ),

我们这里增加一个RasiedButton

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gT51Ukno-1588730588073)(3F79975DABBA4C9F9A8A903C36A6A476)]

我们之前讲过 这个按钮要想设置非常小的按钮我们就要专门对它进行设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0JyciXy-1588730588076)(E5624DE0B2D44034B6EF3589407CD2F3)]

看build方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vR2fcgbc-1588730588080)(FA8C574A02A44C63A0E8E866EE950421)]

它将Theme.of 去出来然后

同时它还获得了一个ButtonTheme

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfX41e4h-1588730588082)(9F317D2CAB844B2EA7259941C5D256CA)]

这里就是因为它设置了这些东西我们才不能把这个按钮变小

      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light,
//        2. 主要样式
        primarySwatch: Colors.red,
//        3. primaryColor: 导航栏和tabBar的颜色
        primaryColor: Colors.green,
//        4. accentColor 这个东西相当于是单独设置floatActionButton这种东西
        accentColor: Colors.blue,
//        5. 还可以设置某些Widget的主题
        buttonTheme: ButtonThemeData(
          height: 25,
          minWidth: 10
        )
      ),

我们这里可以把这个东西

要看原来的 如何设置按钮的最小化 我们可以

  • Day3_6 Align Center Padding Container 单子组件布局
        ButtonTheme (
//        1. 默认情况下Button上下是会有一定的间距的
//        2. Button变小: ButtonTheme
//        3. 取出Button的内边距
//        这个东西是一个Widget所以你可以把它放到这个里面
//        因为你这个东西是要包裹这个东西 那宽度只需要设置不包的时候的最小宽度就可以了
          minWidth: 30,
          height: 10,
          child: FlatButton(
            padding: EdgeInsets.all(0),
            textColor: Colors.white,
            color: Colors.red,
            child: Text("flatButton"),
            materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
            onPressed: () {

            },
          ),
        ),

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BLqXUsgg-1588730588085)(F9E049D0DF1B4C7BB164423D604E9C70)]

这个宽度和高度 在代码里面都是由这个 Theme里面设置这个高宽

      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light,
//        2. 主要样式
        primarySwatch: Colors.red,
//        3. primaryColor: 导航栏和tabBar的颜色
        primaryColor: Colors.green,
//        4. accentColor 这个东西相当于是单独设置floatActionButton这种东西
        accentColor: Colors.blue,
//        5. 还可以设置某些Widget的主题
        buttonTheme: ButtonThemeData(
          height: 6,
          minWidth: 5,
          padding: EdgeInsets.all(0),
          buttonColor: Colors.yellow
        )
      ),

然后按钮里面设置一下 padding 这样

            RaisedButton(
              padding: EdgeInsets.all(0),
              child: Text("点击"),
              onPressed: () {

              },
            )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ePtKW5FW-1588730588087)(AF0F3842022E43539701A9BF2AFA7517)]

  • cardTheme 属性

这个ThemeData的属性可以设置 后面Card的属性

如果设置一个 Card

        child: Column(
          children: [
            Text("hello world"),
            Switch(value: true, onChanged: (value) {

            },),
            CupertinoSwitch(value: true, onChanged: (value) {

            }, activeColor: Colors.red,),
            RaisedButton(
              padding: EdgeInsets.all(0),
              child: Text("点击"),
              onPressed: () {

              },
            ),
            Card(
              child: Text("你好啊, 李银河"),
            )
          ],
        )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f5lm3qKy-1588730588088)(B120F9E7657949A2B9A85F81B78A4E5B)]

同样我们可以 设置 cardTheme的样式

     theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light,
//        2. 主要样式
        primarySwatch: Colors.red,
//        3. primaryColor: 导航栏和tabBar的颜色
        primaryColor: Colors.green,
//        4. accentColor 这个东西相当于是单独设置floatActionButton这种东西
        accentColor: Colors.blue,
//        5. 还可以设置某些Widget的主题
        buttonTheme: ButtonThemeData(
          height: 6,
          minWidth: 5,
          buttonColor: Colors.yellow
        ),
        cardTheme: CardTheme(
          color: Colors.yellow,
          elevation: 10
        )
      ),

同样我们设置这个

cardTheme 这个elevation 属性的作用是设置阴影

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7O6xtDO-1588730588090)(EF33664504584F128E17B1096CA81D85)]

同样我们还可以通过shape还设置边框

这个东西的位置实在Day3_4 flutter基本组件 里面

        FlatButton(
          color: Colors.amberAccent,
//          这个东西非常重要borderRadius
          shape: RoundedRectangleBorder(
            borderRadius: ,
          ),
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              Icon(Icons.favorite, color: Colors.red),
              Text("喜欢作者")
            ],
          ),
          onPressed: () {},
        ),

同样我们可以设置这个东西的圆角

        cardTheme: CardTheme(
          color: Colors.yellow,
          elevation: 10,
          shape: RoundedRectangleBorder(
//              side: BorderSide(
//                width: 10,
//                color: Colors.red,
//              ),
              borderRadius: BorderRadius.circular(8)
          )
        )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oeMnafJh-1588730588092)(47A7AB601E2B4EBBA7294D0A587D7AA9)]

这个也是一个主题

  • 文字的主题 textTheme

这个就很重要考虑

我们想要知道这个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0DhNOBX9-1588730588094)(28300074765042708A686A553E2F6EDD)]

这个text的字体默认的字体大小 是来自于 textTheme里面的字体大小

因为这个是查类的用法 所以

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EOgMof8G-1588730588096)(BABC4760A34D478BA82A78DDCE6F12AD)]

我们们来到 MaterialApp里面 然后看到他们的theme属性
点到他的ThemeData里面去

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CbQZ2EmG-1588730588098)(1F290E03B83E4E38B9B697EABA1911D7)]

你看他这里就有一个accentColor 和 primaryColor的图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a2bv3swe-1588730588100)(488866A2F71643D18C96D1483E5D5559)]

然后来到textTheme进行搜索

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z0wCRXA1-1588730588101)(9F30D5C22DB241A59C7C56D6D23880BD)]

然后点击这个TextTheme这个类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m2Qn6RZL-1588730588105)(AE6189679FBF4A228D6B49EF9CA35DA6)]

在TextTheme有这样的一些属性 他们对textTheme 进行一些 设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BUyh2JLh-1588730588107)(1E7AAAA968C84903876EB3366F98269E)]

也就是说我们在设置这个textTheme 里面进行设置的 一些可以一起定义的样式

这样就相对于 html的样式和结构的分开的方式有点像

我们可以给他设置很多的属性

        textTheme: TextTheme(
          body1: TextStyle(fontSize: 15),
          body2: TextStyle(fontSize: 20),
          display1: TextStyle(fontSize: 25)
        )

那这些body1 display是设置来干什么的呢

这个body1就是默认的项目设置以后 这种默认的文字样式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zB3QFIQY-1588730588109)(2CA8EBD5B4C94BE8B8D000EFF8C159A6)]

然后我们在看到这个 文档里面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kuHZ907X-1588730588113)(4BEF7CDC14E0443886054B2834A119EC)]

这里有一个14sp 也就是说我们的单位的数值就是 14

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i9pyO9Fr-1588730588115)(65F02A827BA14214B33BF8026846F7CF)]

这个样式

        child: Column(
          children: [
            Text("hello world"),
            Text("hello world test", style: TextStyle(fontSize: 14)),
            Switch(value: true, onChanged: (value) {

            },),
            CupertinoSwitch(value: true, onChanged: (value) {

            }, activeColor: Colors.red,),
            RaisedButton(
              padding: EdgeInsets.all(0),
              child: Text("点击"),
              onPressed: () {

              },
            ),
            Card(
              child: Text("你好啊, 李银河", style: TextStyle(fontSize: 50)),
            )
          ],

看到 其实 这个字体的默认宽度就是这body1的14

所以知道这个的话我们就可以改变这个默认的字体大小了

我们来到对应的地方

        textTheme: TextTheme(
          body1: TextStyle(fontSize: 18, color: Colors.red),
//          body2: TextStyle(fontSize: 20),
          display1: TextStyle(fontSize: 25)
        )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y21dZ7jY-1588730588116)(D9B72FE05F88407A95911C6DDF628D9C)]

可以看出这个 字体的样式 其中一个变大了

除了这个body1 body2 又是干什么的呢

这个ThemeData的作用

  • 1.设置默认样式
  • 2.可以通过Theme.of(context) 这样知道 会获取一个InhertiedWidget 这样来获取 这个 之前提前定义过的样式

但是你会发现这个地方他没有继承 InheritedWidget

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4hgDncMZ-1588730588118)(AA32833EBDC04E15B32952C6E9666923)]

那你怎么能通过 of的方式取到Element树里面取到 对应的

我们看到源码里面 它是通过 这个东西拿到一个_InheritedTheme

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bIKOCyND-1588730588121)(CB01B6D69B4C4E7190FC09E5B0F196D2)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M116yVCp-1588730588124)(291A317B166241A8B61E83ADB4C1AD80)]

这个themeData它最后是保存到inheritedTheme 这个对象里面 然后 theme里面 data属性

所以这里of我们其实是拿到了 这个ThemeData对象的

        textTheme: TextTheme(
          body1: TextStyle(fontSize: 18, color: Colors.red),
          body2: TextStyle(fontSize: 20,color: Colors.blue),
          display1: TextStyle(fontSize: 25)
        )
          children: [
            Text("hello world"),
            Text("hello world test", style: TextStyle(fontSize: 14)),
            Text("hello world test3", style: TextStyle(fontSize: 20)),
            Text("hello world test2", style: Theme.of(context).textTheme.body2),

这样我们就可以提前定义这个样式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NGwGaPYs-1588730588126)(DAD3F2820ED74DAEA7B0ADCD4784F4E5)]

而且这个其实已经是一个粗体了

还有display2 这个字体

            Text("hello world"),
            Text("hello world test", style: TextStyle(fontSize: 14)),
            Text("hello world test3", style: TextStyle(fontSize: 20)),
            Text("hello world test2", style: Theme.of(context).textTheme.display2),

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2qHKKG4x-1588730588129)(D81F36B9395544E690AA1D1489710501)]

我们发现这个 字体的大小 太大了 但是 平时我们并不会使用这么大的字体

所以这个时候我们就 会对这个样式自定义设置

        textTheme: TextTheme(
          body1: TextStyle(fontSize: 18, color: Colors.red),
          body2: TextStyle(fontSize: 20,color: Colors.blue),
          display1: TextStyle(fontSize: 14),
          display2: TextStyle(fontSize: 16),
          display3: TextStyle(fontSize: 20),
          display4: TextStyle(fontSize: 24)
        )

我们如果想要用不同大小的字体我们就选用不同的自定义样式

这样我们就可以在统一的地方管理样式

相当于用diaplay来对我们的字体进行统一的管理

当然这里还有一些其他的样式

headline 这个用在一些 大文本里面的弹窗

这个文档你里面其实说的很清楚 用的时候可以自己来看看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vJMzk5fG-1588730588132)(03CE732620B24250BACD66E1546ED5CB)]

还可以看到这个subhead这个地方 ListTile里面的title

所以这里都是对主题的风格进行管理

import 'package:flutter/cupertino.dart';
import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
//        1. 亮度
        brightness: Brightness.light,
//        2. 主要样式
        primarySwatch: Colors.red,
//        3. primaryColor: 导航栏和tabBar的颜色
        primaryColor: Colors.green,
//        4. accentColor 这个东西相当于是单独设置floatActionButton这种东西
        accentColor: Colors.blue,
//        5. 还可以设置某些Widget的主题
        buttonTheme: ButtonThemeData(
          height: 6,
          minWidth: 5,
          buttonColor: Colors.yellow
        ),
        cardTheme: CardTheme(
          color: Colors.yellow,
          elevation: 10,
          shape: RoundedRectangleBorder(
//              side: BorderSide(
//                width: 10,
//                color: Colors.red,
//              ),
              borderRadius: BorderRadius.circular(8)
          )
        ),
        textTheme: TextTheme(
          body1: TextStyle(fontSize: 18, color: Colors.red),
          body2: TextStyle(fontSize: 20,color: Colors.blue),
          display1: TextStyle(fontSize: 14),
          display2: TextStyle(fontSize: 16),
          display3: TextStyle(fontSize: 20),
          display4: TextStyle(fontSize: 24)
        )
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {

//  MaterialColor color = Color(0xff000000);
////  子类的引用不能指向父类

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Column(
          children: [
            Text("hello world"),
            Text("hello world test", style: TextStyle(fontSize: 14)),
            Text("hello world test3", style: TextStyle(fontSize: 20)),
            Text("hello world test2", style: Theme.of(context).textTheme.display2),
            Switch(value: true, onChanged: (value) {

            },),
            CupertinoSwitch(value: true, onChanged: (value) {

            }, activeColor: Colors.red,),
            RaisedButton(
              padding: EdgeInsets.all(0),
              child: Text("点击"),
              onPressed: () {

              },
            ),
            Card(
              child: Text("你好啊, 李银河", style: TextStyle(fontSize: 50)),
            )
          ],
        )
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            title: Text("首页"),
            icon: Icon(Icons.people)
          ),
          BottomNavigationBarItem(
              title: Text("分类"),
              icon: Icon(Icons.people)
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          Navigator.of(context).push(MaterialPageRoute(
            builder: (ctx) {
              return HYDetailPage();
            }
          ));
        },
      ),
    );
  }
}

class HYDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("详情页"),
      ),
      body: Center(
          child: Text("detail Page")
      )
    );
  }
}

主题不仅仅只在本页面生效

可以看到这个页面的 跳转以后 也是会默认使用 body1里面的样式的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eld607qz-1588730588135)(345D436CC5EE4B25BE16D17291CAA97F)]

同时这个 样式对Card里面的样式也是有效的

同时这个 顶部的导航栏 也是绿色的

所以这个地方是 一个全局的主题

    return MaterialApp(
      title: "Flutter Demo",
//      这个是属于一个全局的主题
      theme: ThemeData(
//        1. 亮度

我们也是可以在某个页面使用单独的样式的

我们到 我们新建的页面里面设置 AppBar里面的样式

      appBar: AppBar(
        title: Text("详情页"),
        backgroundColor: Colors.purple
      ),

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2bUM0U2k-1588730588137)(4FF118F656A142469FDF9E2859E20B38)]

所以 一般是Widget只要有设置自己的东西 它就会吧主题的东西覆盖掉

当然我们也可以这样来做 设置它自己的主题

我们可以给这个页面单独包裹一个主题Theme

class HYDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Theme(
      child: Scaffold(
        appBar: AppBar(
          title: Text("详情页"),
          backgroundColor: Colors.purple
        ),
        body: Center(
            child: Text("detail Page")
        ),
      ),
    );
  }
}

这个的原理也是比较好理解的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7qebUgWD-1588730588139)(18242FFA59A544A6ACB515B439CA6327)]

这个就是 我们使用Theme.of往上找的时候就会找到这个Theme里面的东西

它就不会在使用这个主题了

这样我们就可以使用一个局部的主题进行一个覆盖

但是注意我们 一旦把 之前的东西覆盖掉了 那我们 之前所有的全局样式都 覆盖掉了

class HYDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(
        primaryColor: Colors.red,
      ),
      child: Scaffold(
        appBar: AppBar(
          title: Text("详情页"),
//          backgroundColor: Colors.purple
        ),
        body: Center(
            child: Text("detail Page")
        ),
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKdlGIsK-1588730588142)(231F6CA4EC7749CD9EF1F2E9E8B24D9D)]

这个文字的大小就变的比较小了 我们是希望所有的东西都给它覆盖吗

不希望 我们希望其他的属性能给我们继承过来

我们可以使用Theme.of获得这个属性

class HYDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context),
      child: Scaffold(
        appBar: AppBar(
          title: Text("详情页"),
//          backgroundColor: Colors.purple
        ),
        body: Center(
            child: Text("detail Page")
        ),
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dVUvNnks-1588730588144)(F9656155D10F4F799D1E3A0C320EDE48)]

但是这样不就和没有嵌套式一样的吗

所以我们要使用copyWith 这样的话我们之前的样式都式拷贝过去的的但是呢 你也可以传一些自己的样式

你传入的 东西会把原来的东西做一个覆盖

class HYDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        primaryColor: Colors.purple,
      ),
      child: Scaffold(
        appBar: AppBar(
          title: Text("详情页"),
//          backgroundColor: Colors.purple
        ),
        body: Center(
            child: Text("detail Page")
        ),
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YsUCrtlf-1588730588145)(FA15C4451E3F43E98F6BB0D9E63B44DD)]

现在这个效果我们就达到了我们想要的效果

所以我们开发的时候肯定用这个更加方便的模式 很少会自己创建一个ThemeData

但是我们这里 有一个问题

我们给这个新页面增加一个floatActionButton

我们想要通过主题来设置这个东西的颜色

class HYDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
        primaryColor: Colors.purple,
        accentColor: Colors.green
      ),
      child: Scaffold(
        appBar: AppBar(
          title: Text("详情页"),
//          backgroundColor: Colors.purple
        ),
        body: Center(
            child: Text("detail Page")
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.pets),
          onPressed: () {},
        ),
      ),
    );
  }
}

所以这个颜色会是什么呢

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZhZVtEo-1588730588150)(F06AAC6F5E004E6B8C91957B9484509B)]

你会发现这个东西覆盖不掉

那是我们的这个 主题没有生效吗

        floatingActionButton: Theme(
          data: Theme.of(context).copyWith(
            accentColor: Colors.pink
          ),
          child: FloatingActionButton(
            child: Icon(Icons.pets),
            onPressed: () {},
          ),
        ),

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKdDXtI6-1588730588153)(AD291AA8FB5F452C89A0D9F59E356A93)]

但是它还是 蓝色的

这个东西也还是改不掉的

我们来到一个 新的文档页面

这个东西其实中国的一些人翻译了官网的sdk放到上面的东西

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K7VRklrO-1588730588155)(4DEB5B73770243D7B3BE8A19AB669C22)]

点击cookbook

这里有一个使用主题和共享颜色

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2koRIj5E-1588730588157)(16E01C71023548758EDA607A674C0F15)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rOPu2LF4-1588730588159)(E6C7754F68EC45738E7F638FB17DB47D)]

然后看到它设置了一个 全局样式

然后局部的位置和我们使用的方法一样

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Za3psCEY-1588730588162)(585CD2EA92B641479436B13302C6F502)]

你看它这个文档这个是错误的

所以有些东西是错的

我们到其他的地方去看看 我们来到gethub issure里面去看

老师找到一篇回答

https://github.com/material-components/material-components-flutter-codelabs/issues/106

在这个问题下面 flutter的开发人员 对这个回复

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4wEfWcJb-1588730588165)(86E2C6CF18274CB4BBB7C74667DB6D43)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mpexPSRy-1588730588169)(962EEDF2E6BF4AEBB37AC0CB9477C68E)]

不需要知道为什么 你只需要接受它就可以了 ,我们更新了这个accentColor 现在这个东西跑的很好

大家都觉得这个都会生效 甚至中文文档里面这个都是这样写的

好像是因为一开始这个 英文的官方文档里面就是错的

我们找到 CookBook里面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IiP3YCKP-1588730588172)(8DE9CB11EA6F44ED981B09DCF8793C15)]

然后到这里

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KNpvmwkw-1588730588174)(0661F563419C4E3C9A183F6F965BEC9E)]

可以看到它们现在是这样用的

他们这里 使用了一个colorScheme 这个东西

我们不能直接创建这个东西

         floatingActionButton: Theme(
          data: Theme.of(context).copyWith(
            colorScheme: Theme.of(context).colorScheme.copyWith(secondary: Colors.pink),
          ),
          child: FloatingActionButton(
            child: Icon(Icons.pets),
            onPressed: () {},
          ),

这次才正真的把这个改过来了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-80TnV0Eu-1588730588176)(8EEAD8C0BC68421BBB67162B9B184B1A)]

那总之 这个东西 就是这样不能用这个来改

原因很有可能是 这个floatActionButton非常的特殊

他可能是在某个地方对这个accentColor对这个东西做了一个保存 之后他在这里再用这个东西的时候 他就不是通过 Theme.of(context) 来找到这个颜色的

它很有可能是通过这个colorScheme 里面的secondary 来进行保存的

这个就是我们主题的基本使用

import 'package:flutter/cupertino.dart';
import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
//      这个是属于一个全局的主题
      theme: ThemeData(
//        1. 亮度
          brightness: Brightness.light,
//        2. 主要样式
          primarySwatch: Colors.red,
//        3. primaryColor: 导航栏和tabBar的颜色
          primaryColor: Colors.green,
//        4. accentColor 这个东西相当于是单独设置floatActionButton这种东西
          accentColor: Colors.blue,
//        5. 还可以设置某些Widget的主题
          buttonTheme: ButtonThemeData(
              height: 6,
              minWidth: 5,
              buttonColor: Colors.yellow
          ),
          cardTheme: CardTheme(
              color: Colors.yellow,
              elevation: 10,
              shape: RoundedRectangleBorder(
//              side: BorderSide(
//                width: 10,
//                color: Colors.red,
//              ),
                  borderRadius: BorderRadius.circular(8)
              )
          ),
          textTheme: TextTheme(
              body1: TextStyle(fontSize: 18, color: Colors.red),
              body2: TextStyle(fontSize: 20,color: Colors.blue),
              display1: TextStyle(fontSize: 14),
              display2: TextStyle(fontSize: 16),
              display3: TextStyle(fontSize: 20),
              display4: TextStyle(fontSize: 24)
          )
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {

//  MaterialColor color = Color(0xff000000);
////  子类的引用不能指向父类

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text("title")
      ),
      body: Center(
          child: Column(
            children: [
              Text("hello world"),
              Text("hello world test", style: TextStyle(fontSize: 14)),
              Text("hello world test3", style: TextStyle(fontSize: 20)),
              Text("hello world test2", style: Theme.of(context).textTheme.display2),
              Switch(value: true, onChanged: (value) {

              },),
              CupertinoSwitch(value: true, onChanged: (value) {

              }, activeColor: Colors.red,),
              RaisedButton(
                padding: EdgeInsets.all(0),
                child: Text("点击"),
                onPressed: () {

                },
              ),
              Card(
                child: Text("你好啊, 李银河", style: TextStyle(fontSize: 50)),
              )
            ],
          )
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
              title: Text("首页"),
              icon: Icon(Icons.people)
          ),
          BottomNavigationBarItem(
              title: Text("分类"),
              icon: Icon(Icons.people)
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          Navigator.of(context).push(MaterialPageRoute(
              builder: (ctx) {
                return HYDetailPage();
              }
          ));
        },
      ),
    );
  }
}

class HYDetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Theme(
      data: Theme.of(context).copyWith(
          primaryColor: Colors.purple,
          accentColor: Colors.green
      ),
      child: Scaffold(
        appBar: AppBar(
          title: Text("详情页"),
//          backgroundColor: Colors.purple
        ),
        body: Center(
            child: Text("detail Page")
        ),
        floatingActionButton: Theme(
          data: Theme.of(context).copyWith(
              colorScheme: Theme.of(context).colorScheme.copyWith(
                  secondary: Colors.pink
              )
          ),
          child: FloatingActionButton(
            child: Icon(Icons.pets),
            onPressed: () {},
          ),
        ),
      ),
    );
  }
}

暗黑模式的适配

现在ios必须适配暗黑模式

适配这个暗黑模式呢

假如我们的app是用的flutter开发的

如果你想做一个最简单的适配 那么我们因该怎么适配呢

我们只需要增加一个 darkTheme来对这个暗黑状态下的东西进行设置

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.yellow,
        textTheme: TextTheme(
          body1: TextStyle(fontSize: 20, color: Colors.red)
        )
      ),
      darkTheme: ThemeData(
        primarySwatch: Colors.grey,
        textTheme: TextTheme(
          body1: TextStyle(fontSize: 20, color: Colors.green)
        )
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Text("hello")
      ),
    );
  }
}

我们正常状态下它是这样的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rsgbBgVz-1588730588178)(75224AE5EC22432DB4722D788047D2A9)]

暗黑模式下面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gdw8nWEG-1588730588181)(FA311A7F75EE43A29928AD8034A9D1AE)]

这样我们的主题就变了

这样的话我们就不要用三目运算符来进行运算的

这里我们flutter 这里提供了两个 一个是theme 一个是其他的东西

同时还有一个问题就是 我们这个代码越来越多 写再这里肯定不合适 所以

我们可以把它搞在其他地方

我们可以建一个文件夹名叫 shared然后在里面放东西

shared就是基本都是全局共享的文件

建立一个文件叫做 app_theme.dart

建立完这个类的话

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3dzXiMfy-1588730588183)(4C57C23533A94BE09BE46B7C984BCEA6)]

这个地方我们可以使用方法来抽离 也可以使用变量来抽离

import "package:flutter/material.dart";

class HYAppTheme {
//  可以在这里把它封装成一个方法 也可以封装成一个属性
  static final ThemeData norTheme = ThemeData(
      primarySwatch: Colors.yellow,
      textTheme: TextTheme(
          body1: TextStyle(fontSize: 20, color: Colors.red)
      )
  );

  static final ThemeData darkTheme = ThemeData(
      primarySwatch: Colors.grey,
      textTheme: TextTheme(
          body1: TextStyle(fontSize: 20, color: Colors.green)
      )
  );
}

这样我们就把刚刚那坨很大的主题给变干净了

import "package:flutter/material.dart";
import 'package:learn_flutter02/day13_Theme/shared/app_theme.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: HYAppTheme.normalTheme,
      darkTheme: HYAppTheme.darkTheme,
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Text("hello")
      ),
    );
  }
}

结果是一样的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydXxjHFC-1588730588185)(1BEAB941DD274B2FA68F62E20708FA82)]

同时我们还可以进行这种封装

import "package:flutter/material.dart";

class HYAppTheme {
  static const double smallFontSize = 16;
  static const double normalFontSize = 20;
  static const double largeFontSize = 24;

  static final Color normalTextColors = Colors.red;
  static final Color darkTextColors = Colors.green;

//  可以在这里把它封装成一个方法 也可以封装成一个属性
  static final ThemeData norTheme = ThemeData(
      primarySwatch: Colors.yellow,
      textTheme: TextTheme(
          body1: TextStyle(fontSize: normalFontSize, color: normalTextColors)
      )
  );

  static final ThemeData darkTheme = ThemeData(
      primarySwatch: Colors.grey,
      textTheme: TextTheme(
          body1: TextStyle(fontSize: normalFontSize, color: darkTextColors)
      )
  );
}

这样我们改的时候会更加的方便 同时代码也更加简洁

import "package:flutter/material.dart";
import 'package:learn_flutter02/day13_Theme/shared/app_theme.dart';

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme: HYAppTheme.normalTheme,
      darkTheme: HYAppTheme.darkTheme,
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Text("hello")
      ),
    );
  }
}

以后如果我们更需要适配暗黑模式 我们就可以使用这种方式来做

  • 这样我们就不需要在里面的乱起八糟的地方进行修改了

这个是代码维护的一个建议

屏幕的适配

目前移动端还是非常多的

这个时候就有一个问题就是移动端的适配

flutter里面如来做一个适配呢

我们现在有一个手机屏幕

我们给他搞一个Container 我们写一个

Container(
    width: 200,
    height: 200,
    child: Text("hello World")
)

我们写这个200 和 200 到底是什么意思呢

它又没有单位

我们这个时候 我们是面向点开发的

这个点是什么意思呢

我们这里开发的时候是面向逻辑分辨率开发的

并不是物理分辨率

如果我们换一个屏幕 使用 小一点的屏幕

我们用ipone 6来做示范

它的尺寸是多少呢 它的尺寸是一个4.7英寸的尺寸

我们在面向开发的时候
我们一般说它的宽度是375 高度是 667

但是这个单位实际上就是 像素点 来判断的吗

并不是 它这里用的是一个视网膜的一个屏幕 retina

然后有一个devicepixelratio

简称为dpr

有什么用呢 我们的iphone6 它的dpr就是2

它这个水平方向上一个点是两个像素

垂直方向是也是两个像素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vE0rRHHK-1588730588186)(87E32117CDFD4125B007A61C1E3EE233)]

这个时候如果你想要撑满这个屏幕 我们用750 吗 不是我们用 375 就可以了

因为我们现在使用的面向点开发 一个点等于两个像素

  • 所以我们的flutter的默认的单位就是这个点

这个东西我们都是有做记录的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJPYi4qM-1588730588190)(4BB5E7CEC176487A968F90F38E53F53C)]

所以使用的时候注意这个drp的换算

假如我们现在使用 iphone 5 6 7 来做比较

我们 如果在iphone6上面使用这个200 * 200 看起来就还合适 但是放到 iphone上就感觉太小了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A49uBRmx-1588730588192)(A81E6D5AC574409C8ED070B61FA38F64)]

如果我们能在不同的屏幕上展示 不同的大小 那我们不是就能完成这个操作呢

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-01mS7G2S-1588730588195)(B6A9D4247CD74B418C61121A53393253)]

我们这里有很多个 方案 但是我们最终选择一种

现在如果想要做到这样的事情 因为手机屏幕分辨都不一样 我们可能需要经常去拿到对应的东西

宽度 高度 分辨之类的

我们首先会讲如何获得这些东西 但是我们可能是不会用这些东西的

这个东西怎么拿呢 我们一般这个获得屏幕尺寸的东西都希望这个应用程序一旦启动起来就立刻能拿到这个东西

那么我们到 这个程序最先能执行的地方写这个代码 写在哪呢 看起来 虽然 Main里面好像是最先执行的

但是它其实如果写在MyApp的build方法里面话 其实 main里面要先执行runApp函数 它反而没有 写再MyApp的build中快

所以真正因该启动应用程序里面因该拿到这个东西
我们通过一个 window对象拿到这个属性

我们可以通过这样来拿到它的物理宽度和高度

import 'dart:ui';

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    final physicalHeight = window.physicalSize.height;
    print("分辨率: ${physicalWidth } * ${physicalHeight}");

    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Text("hello")
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nDle2zYd-1588730588198)(ECD575505AC7493A9107E031C7A4A28F)]

这样我们就拿到了它的物理宽度和高度

如果我们想要拿到它的逻辑宽度和高度 我们可以通过媒体查询的方式来获得这个东西

import 'dart:ui';

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    1. 手机的物理分辨率
    final physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    final physicalHeight = window.physicalSize.height;
    print("分辨率: ${physicalWidth } * ${physicalHeight}");

//    2. 获得逻辑分辨率 但是这里直接这样写是会报错的
    final logicalWidth = MediaQuery.of(context).size.width;
    final logicalHeight = MediaQuery.of(context).size.height;
    print("逻辑分辨率: ${logicalWidth} * ${logicalHeight}");


    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

但是这里就报错了

原因很简单就是

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cI7LYDTt-1588730588205)(4CDD73BB7C364F64993CBBF06E35A54A)]

这个MediaQuery 并没有准备好 可以看到这个报错信息

但是一旦我们这样写它就不会报错了

import 'dart:ui';

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    1. 手机的物理分辨率
    final physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    final physicalHeight = window.physicalSize.height;
    print("分辨率: ${physicalWidth } * ${physicalHeight}");

    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {


//    2. 获得逻辑分辨率 但是这里直接这样写是会报错的
    final logicalWidth = MediaQuery.of(context).size.width;
    final logicalHeight = MediaQuery.of(context).size.height;
    print("逻辑分辨率: ${logicalWidth} * ${logicalHeight}");

    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Text("hello")
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lmJ0A2k4-1588730588209)(F5971F4FA1D94DDCA3AA42F0BB68550F)]

这个原因就是 MeterialApp还没有初始化完 最主要的就是MediaQuery 没有初始化完

我们点到MediaQuery.of里面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aIJ5B3tB-1588730588214)(109461AC74E3432C93CFEA837E259735)]

可以看到它 这里它也是掉用一个非常熟悉的方法 dependOnInhertiedWidgetO…

它也是用了Inherited去某个地方拿这个MediaQuery这个东西

而它最后返回的是一个data

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-olAL4azA-1588730588216)(42B76A9451F84BC2B1910134A2C0DD7A)]

也就是说你这个data得在使用的时候初始化好

那么这个东西在哪里初始化好呢

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gcm4y00Y-1588730588219)(0350EC47B84540A1B0C479BEC3416CB6)]

我们来到这个MediaQueryData里面

我们看它的构造器 对象初始化的时候 它不就是用的构造器吗

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zOOFfWhq-1588730588221)(567F172EABA94692855563073A1DADCA)]

但是这个对象初始化的时候并没有用它的构造器

你看它的注释 这个地方说 你考虑用这个fromWindow来进行构造

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l8c52cb0-1588730588223)(8EADEDD97FC1451E80B97A0DD3533632)]

其实这里可以去runApp里面一点一点看源码 但是这里我们就不这样做了

它这里用的就是这个MediaQueryData.formWindow这个构造方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DRfXihTk-1588730588225)(154D2C753E8E4CC4961F484048C81D35)]

可以看到这个方法 有一大堆初始化的东西

这个方法必须调完 不然它就会报错

我们来调试一下 给这里两个地方打上断点 然后看看 它是否是先执行这个构造函数然后再执行查询的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lOltrAIM-1588730588228)(42A311419B5F40EE827B7E678DB33E62)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h7397cDp-1588730588230)(D0452335963D4C1DADC70FBCB9610582)]

这样让我们来debug 这个debug太麻烦了 所以一般开发中如果我们能直接打印错误 我们如果可以用其他的 方法查出它的 问题就不会用这个

但是现在我们想看一下 这个代码的执行顺序所以 我们用这个debug的方法来尝试一下

import ‘dart:ui’;

import “package:flutter/material.dart”;

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 1. 手机的物理分辨率
final physicalWidth = window.physicalSize.width; // 拿到物理的宽度
final physicalHeight = window.physicalSize.height;
print(“分辨率: ${physicalWidth } * ${physicalHeight}”);

// 2. 获得逻辑分辨率 但是这里直接这样写是会报错的
final logicalWidth = MediaQuery.of(context).size.width;
final logicalHeight = MediaQuery.of(context).size.height;
print(“逻辑分辨率: ${logicalWidth} * ${logicalHeight}”);

return MaterialApp(
  title: "Flutter Demo",
  theme: ThemeData(
    primarySwatch: Colors.blue,
    splashColor: Colors.transparent
  ),
  home: HYHomeScreen(),
);

}
}

class HYHomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {

return Scaffold(
  appBar: AppBar(
    title: Text("title")
  ),
  body: Center(
    child: Text("hello")
  ),
);

}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oUOlpyIo-1588730588232)(BE6925B198E249D190530C6435C97205)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6iM13q7C-1588730588236)(974D4568194948EF8F7394A677280F55)]

现在你会发现它先执行的这里 MediaQuery.of(context)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RXKVl9u2-1588730588238)(C34805EB993B4DB3A6905ABE24E18AEB)]

因为我们把这个放到前面去了 但是它压根没有执行初始化的代码

同时我们还可以进到这个里面去了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JdtqcJjP-1588730588240)(3F4BDE71926640F48E7B23B1D1054611)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMxImwv2-1588730588241)(B99B810F56544727AEB4903AC27E26D1)]

我们就去就会发现它会首先执行很多的断言

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kGe26eue-1588730588244)(9BFBB1C8BBD644D293029B17DB98B100)]

然后我们发现它这里要初始化最重要的代码就是这个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IEj6YBFt-1588730588247)(28384CDA62884962934BBBEFD957F28B)]

然后我们让它执行 然后把鼠标放到上面 发现我们查到的东西是一个空

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1LWqsDNq-1588730588248)(93931E40C4BE413290A8A1E99D19EC9D)]

为空的时候它就会给你搞一个错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOwldG2i-1588730588251)(A35447C79F394D4F8C0D8FB512C800F3)]

然后下面就看到了 如果我们现在把断点过掉就报错了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0BfrhAGo-1588730588253)(5701045939444B74941B0F57099E94AD)]

我们看到的另外的一个断点就没有执行

这里报的报错就是我们看到的报错

然后我们换过来重新执行一下

import 'dart:ui';

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    1. 手机的物理分辨率
    final physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    final physicalHeight = window.physicalSize.height;
    print("分辨率: ${physicalWidth } * ${physicalHeight}");

    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //    2. 获得逻辑分辨率 但是这里直接这样写是会报错的
    final logicalWidth = MediaQuery.of(context).size.width;
    final logicalHeight = MediaQuery.of(context).size.height;
    print("逻辑分辨率: ${logicalWidth} * ${logicalHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Text("hello")
      ),
    );
  }
}

然后我们看到 第一时间就就执行到了 这个MediaQueryData.fromWindow()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1eo56GNt-1588730588255)(D6B252D39392427CB2E8C433B1FD5046)]

然后我们执行到下一个断点再看一看

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8utSJxpH-1588730588258)(A11B70B9DBA04ACD92960F6BED47F16E)]

执行进去

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uxxuxtwu-1588730588259)(850C6EACFAF44D699B53D49675654949)]

这个时候我们就发现这个东西 不是空了 有执行的时候

它这里就会判断如果你的query不为空那就把这个东西返回

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mvd5GhEa-1588730588263)(879507F3A5AC48FFA1434C18EFF4FD38)]

而这个data就是我们的MediaQueryData的对象

所以 如果你要使用MediaQueryData就只能在下面来使用

而且你这里必须传入一个context

  • 但是我就是想要在这里获取 逻辑宽度和高度

因为我们希望我们第一次构建MyApp的时候就拿好 然后其他的地方就可以使用了 这样我们就不用考虑把这个东西做一个共享 到其他的地方去使用

这个时候怎么办呢

这个时候我们怎么做呢 我们本质上是想要拿 这个MediaQueryData

我们不是想要拿size吗 所以只要我们会看源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i1gP4Fhe-1588730588266)(9D63499630554C398F0C6F40172D7C8E)]

很多东西我们都可以绕过它来做

我们可以看到它其实搞了一个 其实这里本质上用的都是window 那既然我们 都不用

那我们就完全可以绕开这个东西

import 'dart:ui';

import "package:flutter/material.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    1. 手机的物理分辨率
    final physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    final physicalHeight = window.physicalSize.height;
    print("分辨率: ${physicalWidth } * ${physicalHeight}");

//    2. 求出dpr
    final dpr = window.devicePixelRatio;

//    3. 求出逻辑的宽高
    final width = physicalWidth / dpr;
    final height = physicalHeight /dpr;
    print("手动求的逻辑宽高: ${width} * ${height}");
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nvrdBKQh-1588730588268)(B159AA95101944EAA2F19BAE7D19FAB3)]

还有一些东西 这个padding也是有用的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-thK7GZBv-1588730588270)(785E4C6052364530A8B45B1D74E5C5B5)]

如果像是iphonex这种有刘海的话我们就可以求出刘海的高度

同样我们可以拿这个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xiq26TpT-1588730588274)(5101C8D8747742B3971D6EFFDDC7BAD4)]

这个的高度

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //    2. 获得逻辑分辨率 但是这里直接这样写是会报错的
    final logicalWidth = MediaQuery.of(context).size.width;
    final logicalHeight = MediaQuery.of(context).size.height;
    final statusHeight = MediaQuery.of(context).padding.top;
    print("逻辑分辨率: ${logicalWidth} * ${logicalHeight}");
    print("状态栏的高度 ${statusHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Text("hello")
      ),
    );
  }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2WRi7B4F-1588730588276)(0FB2C9298D544451895FEDCEF72133C5)]

同样我们可以手动去拿这个东西

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    1. 手机的物理分辨率
    final physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    final physicalHeight = window.physicalSize.height;
    print("分辨率: ${physicalWidth } * ${physicalHeight}");

//    2. 求出dpr
    final dpr = window.devicePixelRatio;

//    3. 求出逻辑的宽高
    final width = physicalWidth / dpr;
    final height = physicalHeight /dpr;
    print("手动求的逻辑宽高: ${width} * ${height}");

//    4. 状态栏高度
    final statusHeight = window.padding.top / dpr;
    print("手动求的状态栏高度 ${statusHeight}");
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7W7zv6Mg-1588730588278)(7F2431F07BEC40C8AA002E09C65A282B)]

当然这样直接写在外面不好 这个东西其他很多地方可能都会用到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W82Ty52l-1588730588280)(5D1D9BFC8C6240EC90FB8BB2CD693BCA)]

所以我们来新建一个文件将这些代码放到里面去

我们这里用到了window对象 我们可以使用自动导包

  • 自动导包
  • 自动导入文件

alt + enter就是自动导包



import 'dart:ui';

class HYSizeFit {
  static double physicalWidth;
  static double physicalHeight;
  static double screenWidth;
  static double screenHeight;
  static double dpr;
  static double statusHeight;

  static void initialize() {
//    1. 手机的物理分辨率
    physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    physicalHeight = window.physicalSize.height;

//    2. 求出dpr
    dpr = window.devicePixelRatio;
//    3. 求出逻辑的宽高
    screenWidth = physicalWidth / dpr;
    screenHeight = physicalHeight /dpr;

//    4. 状态栏高度
    statusHeight = window.padding.top / dpr;
  }
}

然后在主文件中使用


import "package:flutter/material.dart";
import "shared/size_fit.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    导入文件 然后初始化
    HYSizeFit.initialize();
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("物理宽度高度 ${HYSizeFit.physicalWidth} * ${HYSizeFit.physicalHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
          child: Center(
              child: Text("hello world", style: TextStyle(fontSize: 20))
          ),
        )
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KW6cTp58-1588730588284)(A1BC540C9287442FA41692CA6A82B610)]

屏幕适配

现在我们来搞几个模拟器 iphone 5 6 6+ 其他的东西来使用这个

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("物理宽度高度 ${HYSizeFit.physicalWidth} * ${HYSizeFit.physicalHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
          child: Text("hello world", style: TextStyle(fontSize: 20)),
        )
      ),
    );
  }
}

image

但是我们这只是在小屏幕的iphone上面可以放下

如果我们到 iphone5上面说不定就不行了 他是比较小的

如果我们这里也给他搞一个200 * 200 说不定就不行了 这个时候 如果站的比较多了 这个时候 可能就会报一些错了

所以我们希望你在iphone5 上面 放的小一点 然后再iphone 6 + 上面放的大一点

但是现在如果跑在这些机器上面那他们的距离因该都是200 * 200 这个大小现在是写死的

其实在前端里面对这个东西的适配已经有很多的经验了 所以我们这里借助前端的方案来适配

前端的方案有三种

  • rem
    • 这个东西的方式是 给更标签设置一个字体大小
    • 其他的设置一个字体大小 其他的标签在设置的时候 它就会根据这个字体大小作为单位
  • vw vh
    • 将屏幕分成100 等分 一个vw就是屏幕宽度的1%
    • 其他的所有的单位都使用 vw或者vh
  • rpx
    • 这个是小程序的适配方案 这个东西就是一个可相应的东西
    • 这个东西是 以iphone 6为设计稿
      • 如果我们使用 400 * 400 的时候在iphone 6 上面就是一个200 * 200
      • 如果我们变到到比较的小的上面 这里我们用 400 * 400 它就是 400 * 0.42 作为它的宽度来使用的 这个.42怎么算出来的 是可以 168 这里它就会对这个做一个拉伸
      • 这里我们不管你什么屏幕 我都把你分成 750等份 这个时候iphone 6 就是 0.5 375 / 750
      • iphone 5是 320 / 750 iphone 6+ 414 / 750 0.552
      • 所以这个小程序就和 vw vh差不多 但是它是将屏幕分的更多

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-khX6m4It-1588730588286)(1DD8B4AEFDFC4AFDB4C5D072423877E7)]

那我们怎么做这个适配呢 我们来到size_fit 里面 新建一个属性rpx 然后通过这些东西计算出 rpx



import 'dart:ui';

class HYSizeFit {
  static double physicalWidth;
  static double physicalHeight;
  static double screenWidth;
  static double screenHeight;
  static double dpr;
  static double statusHeight;

  static double rpx;

  static void initialize() {
//    1. 手机的物理分辨率
    physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    physicalHeight = window.physicalSize.height;

//    2. 求出dpr
    dpr = window.devicePixelRatio;
//    3. 求出逻辑的宽高
    screenWidth = physicalWidth / dpr;
    screenHeight = physicalHeight /dpr;

//    4. 状态栏高度
    statusHeight = window.padding.top / dpr;

//    5. 计算rpx
    rpx = screenWidth / 750;
  }
}

其实就是 逻辑宽度和750 的商

然后再其他的地方使用

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("物理宽度高度 ${HYSizeFit.physicalWidth} * ${HYSizeFit.physicalHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Container(
          width: 200 * HYSizeFit.rpx,
          height: 200 * HYSizeFit.rpx,
          color: Colors.red,
          child: Center(
              child: Text("hello world", style: TextStyle(fontSize: 20))
          ),
        )
      ),
    );
  }
}

当然后面我们有更好的适配的写法

但是你注意一个问题就是 小程序里面 我们的是除以 750 不是375 所以我们的所有的东西 都要翻倍

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("物理宽度高度 ${HYSizeFit.physicalWidth} * ${HYSizeFit.physicalHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Container(
          width: 400 * HYSizeFit.rpx,
          height: 400 * HYSizeFit.rpx,
          color: Colors.red,
          child: Center(
              child: Text("hello world", style: TextStyle(fontSize: 40 * HYSizeFit.rpx))
          ),
        )
      ),
    );
  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qzWPp946-1588730588288)(EE7A6FDDA7494736BDE842EF0A0A9DEA)]

这样我们的大小就不一样了

但是 这个地方 * 单位的方式不是特别好些 所以我们这里搞了一个其他的东西

我们给它搞了一个静态方法来实现这个东西



import 'dart:ui';

class HYSizeFit {
  static double physicalWidth;
  static double physicalHeight;
  static double screenWidth;
  static double screenHeight;
  static double dpr;
  static double statusHeight;

  static double rpx;

  static void initialize() {
//    1. 手机的物理分辨率
    physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    physicalHeight = window.physicalSize.height;

//    2. 求出dpr
    dpr = window.devicePixelRatio;

//    3. 求出逻辑的宽高
    screenWidth = physicalWidth / dpr;
    screenHeight = physicalHeight /dpr;

//    4. 状态栏高度
    statusHeight = window.padding.top / dpr;

//    5. 计算rpx
    rpx = screenWidth / 750;
  }

  static double setRpx(double size) {
    return size * rpx;
  }
}

使用

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("物理宽度高度 ${HYSizeFit.physicalWidth} * ${HYSizeFit.physicalHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Container(
          width: HYSizeFit.setRpx(400),
          height: HYSizeFit.setRpx(400),
          color: Colors.red,
          child: Center(
              child: Text("hello world", style: TextStyle(fontSize: HYSizeFit.setRpx(40)))
          ),
        )
      ),
    );
  }
}

但是如果我们这里还是使用这个rpx不是要翻倍吗 不是很好用 所以我们可以再搞一个单位

import 'dart:ui';

class HYSizeFit {
  static double physicalWidth;
  static double physicalHeight;
  static double screenWidth;
  static double screenHeight;
  static double dpr;
  static double statusHeight;

  static double rpx;
  static double px;

  static void initialize() {
//    1. 手机的物理分辨率
    physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    physicalHeight = window.physicalSize.height;

//    2. 求出dpr
    dpr = window.devicePixelRatio;

//    3. 求出逻辑的宽高
    screenWidth = physicalWidth / dpr;
    screenHeight = physicalHeight /dpr;

//    4. 状态栏高度
    statusHeight = window.padding.top / dpr;

//    5. 计算rpx
    rpx = screenWidth / 750;
    px = rpx * 2;
  }

  static double setRpx(double size) {
    return size * rpx;
  }

  static double setPx(double size) {
    return size * px;
  }
}

这样如果ui给的是一个px 就用px 如果用的是一个rpx那就可以用 rpx

有些时候 公司不是以750 为设计稿 所以我们可以封装更加好一点

这里我们可以给这个initialize 传递一个参数 standardSize 还给他整了一个默认参数

import 'dart:ui';

class HYSizeFit {
  static double physicalWidth;
  static double physicalHeight;
  static double screenWidth;
  static double screenHeight;
  static double dpr;
  static double statusHeight;

  static double rpx;
  static double px;

  static void initialize({standardSize = 750}) {
//    1. 手机的物理分辨率
    physicalWidth = window.physicalSize.width; // 拿到物理的宽度
    physicalHeight = window.physicalSize.height;

//    2. 求出dpr
    dpr = window.devicePixelRatio;

//    3. 求出逻辑的宽高
    screenWidth = physicalWidth / dpr;
    screenHeight = physicalHeight /dpr;

//    4. 状态栏高度
    statusHeight = window.padding.top / dpr;

//    5. 计算rpx
    rpx = screenWidth / standardSize;
    px = screenWidth / standardSize * 2;
  }

  static double setRpx(double size) {
    return size * rpx;
  }

  static double setPx(double size) {
    return size * px;
  }
}

还有 一种方案是使用extension 用这个数值参数的 扩展类 然后将 这个写法继续优化

我们新建一个extensio int 这样就相当于在 int类中写东西

但是注意我们的dart是没有 隐式转换的

import "size_fit.dart";

extension IntFit on int {
  double get px {
    return HYSizeFit.setPx(this.toDouble());
  }

  double get rpx {
    return HYSizeFit.setRpx(this.toDouble());
  }
}
import 'package:learn_flutter02/day14_screenfit/shared/size_fit.dart';

extension DoubleFit on double {
//  double px() {
//    return HYSizeFit.setPx(this);
//  }
//
//  double rpx() {
//    return HYSizeFit.setRpx(this);
//  }

  double get px {
    return HYSizeFit.setPx(this);
  }

  double get rpx {
    return HYSizeFit.setRpx(this);
}
}

我梦给他增加一个 方法 来获得对应的 rpx px值

导入对应的文件使用


import "package:flutter/material.dart";
import "shared/size_fit.dart";

import "extension/double_extension.dart";
import "extension/int_extension.dart";

main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
//    导入文件 然后初始化
    HYSizeFit.initialize();
    return MaterialApp(
      title: "Flutter Demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        splashColor: Colors.transparent
      ),
      home: HYHomeScreen(),
    );
  }
}

class HYHomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("物理宽度高度 ${HYSizeFit.physicalWidth} * ${HYSizeFit.physicalHeight}");
    return Scaffold(
      appBar: AppBar(
        title: Text("title")
      ),
      body: Center(
        child: Container(
          width: 400.rpx,
          height: 200.px,
          color: Colors.red,
          child: Center(
              child: Text("hello world", style: TextStyle(fontSize: 40.rpx))
          ),
        )
      ),
    );
  }
}

这种方式更加简洁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z3GLi4JM-1588730588290)(7D1F9CFD54744C1D8B7B264C101E5861)]

你可能感兴趣的:(flutter)