flutter 五点一:MaterialApp Theme

发布时间:2024年01月17日

ThemeData

  factory ThemeData({
    bool? applyElevationOverlayColor,  //material2的darkTheme下 增加一个半透明遮罩 来凸显阴影效果  material3下无效   貌似没啥用
    NoDefaultCupertinoThemeData? cupertinoOverrideTheme,  //ios组件样式  
    Iterable<ThemeExtension<dynamic>>? extensions,  //自定义颜色  可用于统一颜色处理
    InputDecorationTheme? inputDecorationTheme,   //TextField的主题样式
    MaterialTapTargetSize? materialTapTargetSize,   //配置可点击的weight 的点击目标和布局大小
    PageTransitionsTheme? pageTransitionsTheme,  //定义页面过度动画
    ...
}

extensions

  • Iterable<ThemeExtension>? extensions
  • 自定义颜色 可用于统一颜色处理 (定一个常量类不是更简单么 em…)
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

main(){
  runApp(const MyApp());
}

class MyApp extends StatelessWidget{

  const MyApp();

  @override
  Widget build(BuildContext context) {
//定义不同的ThemeData
    ThemeData themeRed = ThemeData.light().copyWith(
      extensions: <ThemeExtension<ThemeColors>>[ThemeColors(themeType: 0)],
    );

    ThemeData themeGreen = ThemeData.light().copyWith(
      extensions: <ThemeExtension<ThemeColors>>[ThemeColors(themeType: 1)],
    );

    ThemeData themeBlue = ThemeData.light().copyWith(
      extensions: <ThemeExtension<ThemeColors>>[ThemeColors(themeType: 2)],
    );

     return MaterialApp(
        theme: themeBlue,   //使用ThemeData  显示不同的颜色
        home: A(),
     );
  }

  void changeTheme(){

  }
}

class ThemeColors extends ThemeExtension<ThemeColors>{

  static String main_color = "main_color";
  static String text_color = "text_color";
  static String text_background = "text_background";

  var themeType = 0;

  var themeRed = {
    main_color:Colors.red,
    text_color:const Color(0xFFD26161),
    text_background:const Color(0xFFEAE4E4),
  };

  var themeGreen = {
    main_color:Colors.green,
    text_color:const Color(0xFF6EDC9A),
    text_background:const Color(0xFFEAE4E4),
  };

  var themeBlue = {
    main_color:Colors.blue,
    text_color:const Color(0xFF6F83E7),
    text_background:const Color(0xFFEAE4E4),
  };


  ThemeColors({this.themeType = 0});
  ThemeColors.themeRed(this.themeRed);
  ThemeColors.themeGreen(this.themeGreen);
  ThemeColors.themeBlue(this.themeBlue);

  @override
  ThemeExtension<ThemeColors> copyWith() {
    var result = null;
    switch(this.themeType){
      case 0:
        result = ThemeColors.themeRed(themeRed);
        break;
      case 1:
        result = ThemeColors.themeGreen(themeGreen);
        break;
      case 2:
        result = ThemeColors.themeBlue(themeBlue);
        break;
    }

    return result;
  }

  @override
  ThemeExtension<ThemeColors> lerp(covariant ThemeExtension<ThemeColors>? other, double t) {
     if(other !is ThemeColors){
        return this;
     }
     var result = null;
     switch(this.themeType){
       case 0:
         result = ThemeColors.themeRed(themeRed);
         break;
       case 1:
         result = ThemeColors.themeGreen(themeGreen);
         break;
       case 2:
         result = ThemeColors.themeBlue(themeBlue);
         break;
     }

     return result;
  }

  Color getColor(String colorName){
    var resultMap = null;
    switch(this.themeType){
      case 0:
        resultMap = themeRed;
        break;
      case 1:
        resultMap = themeGreen;
        break;
      case 2:
        resultMap = themeBlue;
        break;
    }
    return resultMap[colorName];
  }
  
}


class A extends StatefulWidget{

  A(){
    print("A页面启动!");
  }

  @override
  State<StatefulWidget> createState() => AState();
}

class AState extends State<A>{
  @override
  Widget build(BuildContext context) {
    ThemeColors themeColors = Theme.of(context).extension<ThemeColors>()??ThemeColors(themeType: 0);

    return Scaffold(
      backgroundColor: themeColors.getColor(ThemeColors.main_color),  //背景色使用主题的颜色
    );
  }
}

结果
theme: themeRed, //红色
theme: themeGreen, //绿色
theme: themeBlue, //蓝色
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

inputDecorationTheme

  • 输入框的样式 定义输入框各种显示样式及交互样式
 ThemeData themeBlue = ThemeData.light().copyWith(
      extensions: <ThemeExtension<ThemeColors>>[ThemeColors(themeType: 2)],
      inputDecorationTheme: InputDecorationTheme(
        labelStyle: TextStyle(color: Colors.black),  //黑字
        hintStyle: TextStyle(color: Colors.grey),  //hint字体 灰色
        border: UnderlineInputBorder(),    //底部划线边框
        focusedBorder: UnderlineInputBorder(),
      )
    );

属性

const InputDecorationTheme({
    this.labelStyle,
    this.floatingLabelStyle,
    this.helperStyle,
    this.helperMaxLines,
    this.hintStyle,
    this.errorStyle,
    this.errorMaxLines,
    this.floatingLabelBehavior = FloatingLabelBehavior.auto,
    this.floatingLabelAlignment = FloatingLabelAlignment.start,
    this.isDense = false,
    this.contentPadding,
    this.isCollapsed = false,
    this.iconColor,
    this.prefixStyle,
    this.prefixIconColor,
    this.suffixStyle,
    this.suffixIconColor,
    this.counterStyle,
    this.filled = false,
    this.fillColor,
    this.activeIndicatorBorder,
    this.outlineBorder,
    this.focusColor,
    this.hoverColor,
    this.errorBorder,
    this.focusedBorder,
    this.focusedErrorBorder,
    this.disabledBorder,
    this.enabledBorder,
    this.border,
    this.alignLabelWithHint = false,
    this.constraints,
  });

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/7

在这里插入图片描述

materialTapTargetSize

  • 组件最小点击区域
  • 取值 如下
enum MaterialTapTargetSize {
  /// Expands the minimum tap target size to 48px by 48px.  将最小点击目标大小扩展为 48px x 48px。
  ///
  /// This is the default value of [ThemeData.materialTapTargetSize] and the
  /// recommended size to conform to Android accessibility scanner
  /// recommendations.
  padded,

  /// Shrinks the tap target size to the minimum provided by the Material  将点击目标尺寸缩小到Material 规范提供的最小值。
  /// specification.
  shrinkWrap,
}

pageTransitionsTheme

  • 页面切换动画
  • 切换动画支持 android ios macos
    在这里插入图片描述

默认页面切换动画
请添加图片描述

修改后的切换动画 从下往上顶出动画

 pageTransitionsTheme:PageTransitionsTheme(
          builders: <TargetPlatform, PageTransitionsBuilder>{
            TargetPlatform.android:OpenUpwardsPageTransitionsBuilder()
          }
        ),

请添加图片描述
自定义页面切换动画

class MyPageTransitionsBuilder extends PageTransitionsBuilder {

  @override![请添加图片描述](https://img-blog.csdnimg.cn/direct/8874fd6cec764fa4a1b042b4d46bb67d.gif)

  Widget buildTransitions<T>(
      PageRoute<T>? route,
      BuildContext? context,
      Animation<double> animation,    //显示页面执行的动画
      Animation<double> secondaryAnimation,   //隐藏页面执行的动画
      Widget? child,
      ) {
    return ScaleTransition(   //缩放动画  
      scale: animation,
      child: RotationTransition(  //旋转动画
        turns: animation,
        child: child,
      ),
    );
  }
}

结果:B页面旋转放大显示
请添加图片描述
若 return改为如下

return ScaleTransition(  //B页面放大
      scale: animation,
      child: RotationTransition(   //A页面旋转
        turns: secondaryAnimation,
        child: child,
      ),
    );

效果如下
请添加图片描述
其它类型动画 改变return即可 或可仿照系统默认切换动画类改造自己想要的动画

return SizeTransition(
        sizeFactor: animation,
        child: SizeTransition(
          sizeFactor: animation,
          child: child,
    ),
    );

请添加图片描述

全部代码


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

main(){
  runApp(const MyApp());
}

class MyApp extends StatelessWidget{

  const MyApp();

  @override
  Widget build(BuildContext context) {
    ThemeData themeRed = ThemeData.light().copyWith(
      extensions: <ThemeExtension<ThemeColors>>[ThemeColors(themeType: 0)],
    );

    ThemeData themeGreen = ThemeData.light().copyWith(
      extensions: <ThemeExtension<ThemeColors>>[ThemeColors(themeType: 1)],
    );

    ThemeData themeBlue = ThemeData.light().copyWith(
      extensions: <ThemeExtension<ThemeColors>>[ThemeColors(themeType: 2)],
      inputDecorationTheme: InputDecorationTheme(
        labelStyle: TextStyle(color: Colors.black),
        hintStyle: TextStyle(color: Colors.grey),
        border: UnderlineInputBorder(),
        focusedBorder: UnderlineInputBorder(),
      ),
        materialTapTargetSize:MaterialTapTargetSize.shrinkWrap,
        pageTransitionsTheme:PageTransitionsTheme(
          builders: <TargetPlatform, PageTransitionsBuilder>{
            TargetPlatform.android:MyPageTransitionsBuilder()
          }
        ),

    );

     return MaterialApp(
        theme: themeBlue,
        home: A(),
       routes: {
         "/A": (context) => A(),
         "/B": (context) => B(),
         "/C": (context) => C(),
       },
     );
  }

  void changeTheme(){

  }
}

class ThemeColors extends ThemeExtension<ThemeColors>{

  static String main_color = "main_color";
  static String text_color = "text_color";
  static String text_background = "text_background";

  var themeType = 0;

  var themeRed = {
    main_color:Colors.red,
    text_color:const Color(0xFFD26161),
    text_background:const Color(0xFFEAE4E4),
  };

  var themeGreen = {
    main_color:Colors.green,
    text_color:const Color(0xFF6EDC9A),
    text_background:const Color(0xFFEAE4E4),
  };

  var themeBlue = {
    main_color:Colors.blue,
    text_color:const Color(0xFF6F83E7),
    text_background:const Color(0xFFEAE4E4),
  };


  ThemeColors({this.themeType = 0});
  ThemeColors.themeRed(this.themeRed);
  ThemeColors.themeGreen(this.themeGreen);
  ThemeColors.themeBlue(this.themeBlue);

  @override
  ThemeExtension<ThemeColors> copyWith() {
    var result = null;
    switch(this.themeType){
      case 0:
        result = ThemeColors.themeRed(themeRed);
        break;
      case 1:
        result = ThemeColors.themeGreen(themeGreen);
        break;
      case 2:
        result = ThemeColors.themeBlue(themeBlue);
        break;
    }

    return result;
  }

  @override
  ThemeExtension<ThemeColors> lerp(covariant ThemeExtension<ThemeColors>? other, double t) {
     if(other !is ThemeColors){
        return this;
     }
     var result = null;
     switch(this.themeType){
       case 0:
         result = ThemeColors.themeRed(themeRed);
         break;
       case 1:
         result = ThemeColors.themeGreen(themeGreen);
         break;
       case 2:
         result = ThemeColors.themeBlue(themeBlue);
         break;
     }

     return result;
  }

  Color getColor(String colorName){
    var resultMap = null;
    switch(this.themeType){
      case 0:
        resultMap = themeRed;
        break;
      case 1:
        resultMap = themeGreen;
        break;
      case 2:
        resultMap = themeBlue;
        break;
    }
    return resultMap[colorName];
  }
  
}


class A extends StatefulWidget{

  A(){
    print("A页面启动!");
  }

  @override
  State<StatefulWidget> createState() => AState();
}

class AState extends State<A>{
  @override
  Widget build(BuildContext context) {
    ThemeColors themeColors = Theme.of(context).extension<ThemeColors>()??ThemeColors(themeType: 0);


    return Scaffold(
      backgroundColor: themeColors.getColor(ThemeColors.main_color),
      body: Container(
        child: Column(
          children: [
            // TextField(
            //   decoration: InputDecoration(
            //     hintText: "请输入内容"
            //   ),
            // ),
            TextButton(onPressed: (){
              Navigator.pushNamed(context, '/B');
            }, child: Text("B"),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.green),
                padding: MaterialStateProperty.all(EdgeInsets.all(100))
              ),
            ),
            TextButton(onPressed: (){
              Navigator.pushNamed(context, '/C');
            }, child: Text("C"),
              style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.red),
                  padding: MaterialStateProperty.all(EdgeInsets.all(100)),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class B extends StatefulWidget{

  B(){
    print("B页面启动!");
  }

  @override
  State<StatefulWidget> createState() => BState();
}

class BState extends State<B>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"),
      ),
    );
  }
}

class C extends StatefulWidget{
  @override
  State<StatefulWidget> createState() => CState();
}

class CState extends State<C>{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("CCCCCCCCCCCCCCCCCCCCCCCCC"),
      ),
    );
  }
}


class MyPageTransitionsBuilder extends PageTransitionsBuilder {

  @override
  Widget buildTransitions<T>(
      PageRoute<T>? route,
      BuildContext? context,
      Animation<double> animation,
      Animation<double> secondaryAnimation,
      Widget? child,
      ) {
    // return ScaleTransition(
    //   scale: animation,
    //   child: RotationTransition(
    //     turns: secondaryAnimation,
    //     child: child,
    //   ),
    // );
    return SizeTransition(
        sizeFactor: animation,
        child: SizeTransition(
          sizeFactor: animation,
          child: child,
    ),
    );
  }
}

其他分享

  • 学习过程中最大的方式就是查看源码
    比如pageTransitionsTheme 此属性传什么值 怎么传
    Android Studio 使用 Ctrl+左键
    在这里插入图片描述

Ctrl+左键 点击
在这里插入图片描述
需要一个 builders参数
并且有个 defalutBuilder
基本上可以知道怎么使用

再加上 百度/google 搞定!

文章来源:https://blog.csdn.net/weixin_41648633/article/details/135405689
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。