搜索插件、代码仓与 APP 分类

插件详情v4.1.0

one_context

OneContext 提供了一种简单的方法来处理对话框、覆盖层、导航、主题* 和 MediaQuery*,而无需使用 BuildContext。

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
1160
喜欢数
209
Pub 分数
140

安装插件

flutter pub add one_context

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

OneContext 是一个 Flutter/Dart 包,可简化处理对话框、覆盖层、导航以及访问主题和媒体查询数据,而无需使用 BuildContext。它提供全局方法来管理整个 widget 树中的应用状态和 UI 交互,使从应用程序的任何位置显示警报、导航或获取上下文相关值变得更加容易。非常适合减少样板代码并提高复杂 Flutter 应用程序的代码可维护性。

适合场景

  • 显示对话框时没有 BuildContext
  • 应用中的全局导航
  • 全局访问主题和媒体查询数据
  • 管理叠加层和弹出窗口
  • 简化UI元素的状态管理
  • 减少对BuildContext的依赖,以在工具函数中使用

主要特点

  • 无需 BuildContext
  • 全局对话框和覆盖层管理
  • 从任意位置轻松导航
  • 全局访问 Theme 和 MediaQuery
  • 最少的样板代码
  • 跨平台支持

适合对象

  • 大规模 Flutter 应用
  • 寻求更简单上下文处理的开发者
  • 频繁弹出对话框和覆盖层的应用
  • 希望保持一致 UI 行为的团队
  • 旨在减少 BuildContext 依赖的项目
  • 需要全局访问的实用函数

使用建议

  • 可能绕过标准 widget 生命周期
  • 在简单情况下存在过度使用风险
  • 需要仔细的状态管理
  • 不适合用于深度嵌套的上下文相关逻辑
  • 有限的调试可见性
  • 最好与清晰的架构边界配合使用

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

Fork   Star   Watches

Pub Version PRs Welcome

logo

One Context to rule them all

OneContext provides a simple way to deal with Dialogs, Overlays, Navigations, Theme* and MediaQuery* with no need of BuildContext.

If you are Flutter developer, you don’t have to learn something new. This package use the same identificators and names from framework. It’s not a specialized* implementation, so you have the power to create and do not get blocked because of that.

If you are Flutter package developer, OneContext can be very useful too! You can create a custom dialogs package with no need BuildContext, and release a version, that do not depends of the context, to the comunity.

one_context_demo

BuildContext always is needed (in some cases we need to choose carefully the specific one to make things work as expected), but, to global things, like dialogs, it can be reached by OneContext package. 🎯

🎮 Let's start

⚠ Important: Configure MaterialApp. e.g.

/// important: Use [OneContext().builder] in `MaterialApp` builder, in order to show dialogs and overlays.
/// important: Use [OneContext().key] in `MaterialApp` navigatorKey, in order to navigate.
return MaterialApp(
    builder: OneContext().builder,
    navigatorKey: OneContext().key,
    ...
);
There are 2 ways to get OneContext singleton instance, OneContext() or OnceContext.intance. e.g.
    OneContext().pushNamed('/detail_page');
    OneContext.instance.pushNamed('/detail_page');
There are controllers to use navigation, overlays and dialogs. e.g.
    OneContext().navigator.pushNamed(...);
    OneContext().dialog.showDialog(...);
    OneContext().overlay.addOverlay(...);
Or, you can use the shortcuts ;)
    OneContext().pushNamed(...);
    OneContext().showDialog(...);
    OneContext().addOverlay(...);
    
    // and can access info from:
    // OneContext().mediaQuery ...
    // OneContext().textTheme ...
    // OneContext().theme ...
OneContext is:
  • Fast (O(1))
  • Easy to learn/use
  • It use same native function names from Flutter, to keep it simple and intuitive ;)

💬 How to show Dialogs with no need of the BuildContext?

// example snackBar
OneContext().showSnackBar(
    builder: (_) => SnackBar(content: Text('My awesome snackBar!'))
);
// example dialog
OneContext().showDialog(
    // barrierDismissible: false,
    builder: (_) => AlertDialog( 
        title: new Text("The Title"),
        content: new Text("The Body"),
    )
);
// example bottomSheet
OneContext().showBottomSheet(
    builder: (context) => Container(
    alignment: Alignment.topCenter,
    height: 200,
    child: IconButton(
        icon: Icon(Icons.arrow_drop_down),
        iconSize: 50,
        color: Colors.white,
        onPressed: () => Navigator.of(context).pop('sucess')), // or OneContext().popDialog('sucess');
    ),
);
// example modalBottomSheet
OneContext().showModalBottomSheet<String>(
    builder: (context) => Container(
        child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
            ListTile(
                leading: Icon(Icons.music_note),
                title: Text('Music'),
                onTap: () => OneContext().popDialog('Music'); //Navigator.of(context).pop('Music')),
            ListTile(
                leading: Icon(Icons.videocam),
                title: Text('Video'),
                onTap: () => Navigator.of(context).pop('Video'),
            ),
            SizedBox(height: 45)
            ],
        ),
    )
);

⛵ How to navigate? (All methods from Navigator Class are available)

// go to second page using named route
OneContext().pushNamed('/second');
// go to second page using MaterialPageRoute
OneContext().push(MaterialPageRoute(builder: (_) => SecondPage()));
// go back from second page
OneContext().pop();
// Pop dialogs
OneContext().popDialog();
// Retrieve data from route when it's pops
String result = await OneContext().push<String>(MaterialPageRoute(builder: (_) => SecondPage()));
print(result);

🍰 How to show Overlays?

// show the default progress indicator
OneContext().showProgressIndicator();
// hide the default progress indicator
OneContext().hideProgressIndicator();
// show the default progress indicator with some colors
OneContext().showProgressIndicator(
    backgroundColor: Colors.blue.withOpacity(.3),
    circularProgressIndicatorColor: Colors.white
);

// Later
OneContext().hideProgressIndicator();
// Show a custom progress indicator
OneContext().showProgressIndicator(
    builder: (_) => MyAwesomeProgressIndicator();
);

// Later
OneContext().hideProgressIndicator();
// Show a custom widget in overlay stack

String myCustomAndAwesomeOverlayId = UniqueKey().toString();

OneContext().addOverlay(
    overlayId: myCustomAndAwesomeOverlayId,
    builder: (_) => MyCustomAndAwesomeOverlay()
);

// Later
OneContext().removeOverlay(myCustomAndAwesomeOverlayId);

🎨 Changing Dark and Light theme mode

Breaking change: OneHotReload becomes OneNotification
⚠ Please check consideration on Theme and MediaQuery topic
OneNotification<OneThemeChangerEvent>(
  stopBubbling: true, // avoid bubbling to ancestors
  builder: (_, __) {
    return MaterialApp(
      builder: OneContext().builder,
      themeMode: OneThemeController.initThemeMode(ThemeMode.light),
      theme: OneThemeController.initThemeData(ThemeData(brightness: Brightness.light)),
      darkTheme: OneThemeController.initDarkThemeData(ThemeData(brightness: Brightness.dark)),
      ...
    );
);

// Later...
OneContext().oneTheme.toggleMode();

// Or change only the dark theme
OneContext().oneTheme.changeDarkThemeData(
  ThemeData(
    primarySwatch: Colors.amber,
    brightness: Brightness.dark
 )
);

🚧 Reload, Restart and Reboot the app (Need bubbling events or data?)

First define the data type in type generics, after that, you can rebuild multiple ancestors widgets that listen the same data type. This is used for the package in this example, to change ThemeMode and Locale and even Restart the app entirely.
OneNotification<List<Locale>>(
      onVisited: (context, localeList) {
        print('widget visited!');
      },
      stopBubbling: true, // avoid the data bubbling to ancestors widgets
      initialData: _localeEnglish, // [data] is null during boot of the application, but you can set initialData
      rebuildOnNull: true, // Allow other entities reload this widget without messing up currenty data (Data is cached on first event)
      builder: (context, localeList) {
        return MaterialApp(
          supportedLocales: localeList,
        );
      },
    );
Need to dispatch more specialized data/event?

// My Specialized Event
class MySpecializedEvent {
  final String text;
  MySpecializedEvent(this.text);
}

// Widget
OneNotification<MySpecializedEvent>(
  builder: (context, event) {
    return Text(event.text);
  },
)

// Later, in children, call `OneNotifier.notify` to get ancestors notified
OneNotifier.notify(
  context,
  NotificationPayload(
    data: MySpecializedEvent('Nice!');
  )
);
Reload and Restart the app
// Place that widget on most top
OneNotification(
  builder: (_, __) => child
);

// Later... in children

// Dont lose state
OneNotification.softReloadRoot(context);

// Lose state
OneNotification.hardReloadRoot(context);
Reboot and load different apps
// Set the main() function
void main() => OnePlatform.app = () => MyApp();

// Later... Call reboot without recreating root app
OnePlatform.reboot();

// Later... Call reboot recreating the entire application
OnePlatform.reboot(
  builder: () => MyApp()
);

// You even can load an entire different app
OnePlatform.reboot(
  builder: () => MyApp2()
);

⚙ Theme and MediaQuery

print('Platform: ' + OneContext().theme.platform); // TargetPlatform.iOS
print('Orientation: ' + OneContext().mediaQuery.orientation); // Orientation.portrait

[IMPORTANT] If you need get widget rebuild on theme data changes using OneContext().oneTheme.toggleMode();, please consider to use the traditional way Theme.of(context) when getting theme data inside widget.

@override
  Widget build(BuildContext context) {

    return Container(
      color: Theme.of(context).primaryColor, // Theme.of(context)
      height: 100,
      width: 100,
    );
  }

Or you can call Theme.of(context); in the begining of build method instead;

e.g.

@override
  Widget build(BuildContext context) {
    
    // Get changes by you currently context, and ensure the rebuild on theme data changes on
    // OneContext().oneTheme.toggleMode(), OneContext().oneTheme.changeDarkThemeData() or OneContext().oneTheme.changeThemeData() events.
    Theme.of(context);

    return Container(
      color: OneContext().theme.primaryColor, // OneContext().theme
      height: 100,
      width: 100,
    );
  }

In initState or inside class constructor (now it's possible)
@override
  void initState() {
    super.initState();

    OneContext().showDialog(
        builder: (_) => AlertDialog(
          title: new Text("On Page Load"),
          content: new Text("Hello World!"),
        ),
      );

🚦 Warnings

* OneContext().theme and OneContext().mediaQuery are global instances of the root of the widget tree. Use it with care! It can reproduce unexpected behavior if you don't understand it.

* OneContext().context is like a root context, so, it should not be used directly, as it can reproduce unexpected behaviors, unless you have a understanding how it works. It shouldn't work well with InheritedWidget for example.

* This package only uses specialized implementation in Overlays, to make things easy and ensure a quick start.

👨‍💻👨‍💻 Contributing

Contributions of any kind are welcome! I'll be glad to analyse and accept them! 👾
Sponsor

Buy Me A Coffee

所属分类

依赖

依赖清单 2 项

源码仓库

使用此插件的项目

暂无相关数据。