Flutter JSON主题管理插件json_theme的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter JSON主题管理插件json_theme的使用

目录

json_theme

json_theme 是一个用于将Flutter中的 ThemeData 和相关对象编码和解码为JSON格式的库。这目前是该库的早期版本。

这个库主要提供了两个类:

  • ThemeDecoder:提供从JSON映射中解码主题相关对象的功能。
  • ThemeEncoder:提供将主题相关对象编码为JSON映射的功能。

注意事项

  • 编码和解码在大多数情况下是双向兼容的,但不是完全双向兼容的。这是因为主题对象中的一些属性只存在于构造函数中,并没有重新暴露为属性,而是一些动态计算的值。
  • 一些自定义类(如 ShapeSliderDecoration)无法有意义地编码为JSON或从JSON解码。
  • 解码器利用JSON Schema验证器确保JSON格式正确。默认情况下,在调试模式下启用此验证,而在发布模式下出于性能原因禁用此验证。

Live Example

你可以通过以下链接查看在线示例:

Decoding

框架接受JSON兼容的对象以及实际的具体实例传递给 decode 函数。例如:

var appBarTheme = ThemeDecoder.decodeAppBarTheme({
  'brightness': Brightness.dark,
  'color': '#ffdddddd'
}, validate: false);

Schema Validation

框架内置了一个JSON Schema验证器,默认情况下在调试模式下启用,但在发布和配置模式下禁用。你可以通过以下方式全局禁用验证:

import 'package:json_theme/json_theme_schemas.dart';

void main() {
  SchemaValidator.enabled = false;

  /// 应用程序初始化代码
}

Class Selection

尽可能地复制Dart API中的名称。然而,对于某些类(如 Shape 对象)或枚举(如 VerticalDirection),它们的表示方式有所不同。以下是部分类的选择规则:

  • Alignment

    • bottomCenter => Alignment.bottomCenter
    • bottomLeft => Alignment.bottomLeft
  • AutovalidateMode

    • always => AutovalidateMode.always
    • disabled => AutovalidateMode.disabled
  • Axis

    • horizontal => Axis.horizontal
    • vertical => Axis.vertical
  • BlendMode

    • clear => BlendMode.clear
    • color => BlendMode.color
  • BorderRadius

    • all => BorderRadius.all
    • circular => BorderRadius.circular
  • BorderStyle

    • none => BorderStyle.none
    • solid => BorderStyle.solid
  • BottomNavigationBarType

    • fixed => BottomNavigationBarType.fixed
    • shifting => BottomNavigationBarType.shifting
  • BoxFit

    • contain => BoxFit.contain
    • cover => BoxFit.cover
  • ButtonBarLayoutBehavior

    • constrained => ButtonBarLayoutBehavior.constrained
    • padded => ButtonBarLayoutBehavior.padded
  • ButtonTextTheme

    • accent => ButtonTextTheme.accent
    • normal => ButtonTextTheme.normal
  • Clip

    • antiAlias => Clip.antiAlias
    • antiAliasWithSaveLayer => Clip.antiAliasWithSaveLayer
  • CrossAxisAlignment

    • baseline => CrossAxisAlignment.baseline
    • center => CrossAxisAlignment.center
  • CrossFadeState

    • showFirst => CrossFadeState.showFirst
    • showSecond => CrossFadeState.showSecond
  • DecorationPosition

    • background => DecorationPosition.background
    • foreground => DecorationPosition.foreground
  • DragStartBehavior

    • down => DragStartBehavior.down
    • start => DragStartBehavior.start
  • FilterQuality

    • high => FilterQuality.high
    • low => FilterQuality.low
  • FlexFit

    • loose => FlexFit.loose
    • tight => FlexFit.tight
  • FloatingActionButtonAnimator

    • scaling => FloatingActionButtonAnimator.scaling
  • FloatingActionButtonLocation

    • centerDocked => FloatingActionButtonLocation.centerDocked
    • centerFloat => FloatingActionButtonLocation.centerFloat
  • FloatingLabelBehavior

    • always => FloatingLabelBehavior.always
    • auto => FloatingLabelBehavior.auto
  • FontWeight

    • bold => FontWeight.bold
    • normal => FontWeight.normal
  • FontStyle

    • italic => FontStyle.italic
    • normal => FontStyle.normal
  • Gradient

    • linear => LinearGradient
    • radial => RadialGradient
  • HitTestBehavior

    • deferToChild => HitTestBehavior.deferToChild
    • opaque => HitTestBehavior.opaque
  • ImageProvider

    • asset => AssetImage
    • memory => MemoryImage
  • ImageRepeat

    • noRepeat => ImageRepeat.noRepeat
    • repeat => ImageRepeat.repeat
  • InputBorder

    • outline => OutlineInputBorder
    • underline => UnderlineInputBorder
  • InteractiveInkFeatureFactory

    • splash => InkSplash.splashFactory
    • ripple => InkRipple.splashFactory
  • MainAxisAlignment

    • center => MainAxisAlignment.center
    • end => MainAxisAlignment.end
  • MainAxisSize

    • min => MainAxisSize.min
    • max => MainAxisSize.max
  • MaterialTapTargetSize

    • padded => MaterialTapTargetSize.padded
    • shrinkWrap => MaterialTapTargetSize.shrinkWrap
  • MaterialType

    • button => MaterialType.button
    • canvas => MaterialType.canvas
  • MaxLengthEnforcement

    • enforced => MaxLengthEnforcement.enforced
    • none => MaxLengthEnforcement.none
  • MouseCursor

    • defer => MouseCursor.defer
    • material => MouseCursor.material
  • NavigationRailLabelType

    • all => NavigationRailLabelType.all
    • none => NavigationRailLabelType.none
  • NotchedShape

    • circular => CircularNotchedRectangle
  • OutlinedBorder

    • stadium => BeveledRectangleBorder
    • circle => CircleBorder
  • PageTransitionsBuilder

    • clip => Overflow.clip
    • visible => Overflow.visible
  • Radius

    • circular => Radius.circular
    • elliptical => Radius.elliptical
  • RangeSliderThumbShape

    • round => RoundRangeSliderThumbShape
  • RangeSliderTickMarkShape

    • round => RoundRangeSliderTickMarkShape
  • RangeSliderTrackShape

    • rectangular => RectangularRangeSliderTrackShape
    • rounded => RoundedRectRangeSliderTrackShape
  • RangeSliderValueIndicatorShape

    • paddle => PaddleRangeSliderValueIndicatorShape
    • rectangular => RectangularRangeSliderValueIndicatorShape
  • Rect

    • center => Rect.fromCenter
    • circle => Rect.fromCircle
  • ScrollPhysics

    • always => AlwaysScrollableScrollPhysics
    • bouncing => BouncingScrollPhysics
  • ScrollViewKeyboardDismissBehavior

    • manual => ScrollViewKeyboardDismissBehavior.manual
    • onDrag => ScrollViewKeyboardDismissBehavior.onDrag
  • ShapeBorder

    • circle => CircleBorder
    • rectangle => ContinuousRectangleBorder
  • ShowValueIndicator

    • always => ShowValueIndicator.always
    • never => ShowValueIndicator.never
  • SliderComponentShape

    • noOverlay => SliderComponentShape.noOverlay
  • SliderTickMarkShape

    • noTickMark => SliderTickMarkShape.noTickMark
  • SliderTrackShape

    • rectangular => RectangularSliderTrackShape
    • rounded => RoundedRectSliderTrackShape
  • SmartDashesType

    • disabled => SmartDashesType.disabled
    • enabled => SmartDashesType.enabled
  • SmartQuotesType

    • disabled => SmartQuotesType.disabled
    • enabled => SmartQuotesType.enabled
  • SnackBarBehavior

    • fixed => SnackBarBehavior.fixed
    • floating => SnackBarBehavior.floating
  • StackFit

    • expand => StackFit.expand
    • loose => StackFit.loose
  • TabBarIndicatorSize

    • label => ButtonTextTheme.label
    • tab => ButtonTextTheme.tab
  • TargetPlatform

    • android => TargetPlatform.android
    • fuchsia => TargetPlatform.fuchsia
  • TextAlign

    • center => TextAlign.center
    • end => TextAlign.end
  • TextAlignVertical

    • bottom => TextAlignVertical.bottom
    • center => TextAlignVertical.center
  • TextBaseline

    • alphabetic => TextBaseline.alphabetic
    • ideographic => TextBaseline.ideographic
  • TextCapitalization

    • characters => TextCapitalization.characters
    • none => TextCapitalization.none
  • TextDecoration

    • lineThrough => TextDecoration.lineThrough
    • none => TextDecoration.none
  • TextDecorationStyle

    • dashed => TextDecorationStyle.dashed
    • dotted => TextDecorationStyle.dotted
  • TextDirection

    • ltr => TextDirection.ltr
    • rtl => TextDirection.rtl
  • TextInputAction

    • continueAction => TextInputAction.continueAction
    • done => TextInputAction.done
  • TextInputType

    • datetime => TextInputType.datetime
    • emailAddress => TextInputType.emailAddress
  • TextOverflow

    • clip => TextOverflow.clip
    • ellipsis => TextOverflow.ellipsis
  • TextWidthBasis

    • longestLine => TextWidthBasis.longestLine
    • parent => TextWidthBasis.parent
  • TileMode

    • clamp => TileMode.clamp
    • decal => TileMode.decal
  • VerticalDirection

    • down => VerticalDirection.down
    • up => VerticalDirection.up
  • VisualDensity

    • adaptivePlatformDensity => VisualDensity.adaptivePlatformDensity
    • comfortable => VisualDensity.comfortable

示例代码

下面是一个完整的示例代码,展示了如何使用 json_theme 插件来实现主题切换功能:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:json_theme/json_theme.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: RootPage(),
    );
  }
}

class RootPage extends StatefulWidget {
  const RootPage({super.key});

  @override
  State createState() => _RootPageState();
}

class _RootPageState extends State<RootPage> {
  static const _themes = [
    'default',
    'big_red',
    'calm_blue',
  ];

  Future<void> _onThemeSelected(BuildContext context, String themeId) async {
    final navigator = Navigator.of(context);
    final themeStr = await rootBundle.loadString('assets/themes/$themeId.json');
    final themeJson = json.decode(themeStr);

    final theme = ThemeDecoder.decodeThemeData(
          themeJson,
          validate: true,
        ) ??
        ThemeData();

    if (mounted) {
      await navigator.push(
        MaterialPageRoute(
          builder: (BuildContext context) => ThemePage(
            theme: theme,
          ),
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Select Theme'),
      ),
      body: ListView.builder(
        itemCount: _themes.length,
        itemBuilder: (BuildContext context, int index) => ListTile(
          title: Text(_themes[index]),
          onTap: () => _onThemeSelected(context, _themes[index]),
        ),
      ),
    );
  }
}

class ThemePage extends StatelessWidget {
  final ThemeData theme;

  const ThemePage({super.key, required this.theme});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: theme,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Theme Page'),
        ),
        body: Center(
          child: Text(
            'This page is using the selected theme!',
            style: TextStyle(fontSize: 20),
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的应用,允许用户从几个预定义的主题中选择一个。每个主题存储在一个JSON文件中,并通过 json_theme 插件进行加载和应用。用户选择主题后,导航到一个新的页面,该页面使用所选主题进行渲染。


更多关于Flutter JSON主题管理插件json_theme的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter JSON主题管理插件json_theme的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter应用中使用json_theme插件进行JSON主题管理的代码案例。json_theme插件允许你从JSON文件中加载主题配置,并应用到你的Flutter应用中。

步骤 1: 添加依赖

首先,你需要在pubspec.yaml文件中添加json_theme依赖:

dependencies:
  flutter:
    sdk: flutter
  json_theme: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

步骤 2: 创建JSON主题文件

在你的assets文件夹中创建一个JSON文件,例如themes.json,内容如下:

{
  "lightTheme": {
    "primaryColor": "#ffffff",
    "backgroundColor": "#eeeeee",
    "textColor": "#000000"
  },
  "darkTheme": {
    "primaryColor": "#000000",
    "backgroundColor": "#222222",
    "textColor": "#ffffff"
  }
}

步骤 3: 加载JSON主题

在你的Flutter应用中,你需要加载这个JSON文件并应用主题。首先,确保在pubspec.yaml中声明你的JSON文件为资产:

flutter:
  assets:
    - assets/themes.json

然后,在你的主文件中(例如main.dart),你可以这样做:

import 'package:flutter/material.dart';
import 'package:json_theme/json_theme.dart';
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 加载JSON主题
  final String jsonContent = await rootBundle.loadString('assets/themes.json');
  final Map<String, dynamic> themeData = jsonDecode(jsonContent);

  // 将JSON数据转换为JsonThemeData
  final JsonThemeData jsonThemeData = JsonThemeData.fromJson(themeData);

  // 获取特定的主题,例如lightTheme
  final ThemeData lightTheme = jsonThemeData.theme('lightTheme')!;

  runApp(MaterialApp(
    theme: lightTheme,
    home: MyHomePage(),
  ));
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('JSON Theme Example'),
      ),
      body: Center(
        child: Text(
          'Hello, World!',
          style: TextStyle(color: Theme.of(context).textTheme.bodyText1!.color),
        ),
      ),
    );
  }
}

步骤 4: 使用主题

现在,你的应用已经加载并应用了从JSON文件中读取的主题。你可以使用Theme.of(context)在任何地方访问当前主题。

注意事项

  1. JSON结构:确保你的JSON文件结构与json_theme插件的要求相匹配。你可能需要调整JSON结构以匹配插件的期望格式。
  2. 错误处理:在实际应用中,你应该添加适当的错误处理,例如处理文件加载失败或JSON解析错误。
  3. 动态切换主题:虽然上面的例子只展示了如何加载和应用一个主题,但json_theme插件也支持动态切换主题。你可以根据用户的选择或其他条件动态加载不同的主题。

这个代码案例应该能帮助你开始在Flutter应用中使用json_theme插件进行JSON主题管理。如果你有更多具体需求或遇到问题,请查阅json_theme的官方文档或提出具体问题。

回到顶部