Flutter 平台小部件

通过一组通用的平台感知小部件,针对 Android 的 Material 设计和 iOS 的 Cupertino 设计。

此项目旨在探索是否可以创建具有平台感知能力的小部件。目前,为了渲染特定于 Android 或 iOS 设备的样式,您需要条件性地检查平台,或者创建一组根据运行平台不同而渲染不同的小部件。

小部件

这组小部件允许使用一套单一的跨平台小部件来进行基于目标平台的渲染。

android

ios

每个 `PlatformWidget` 都将通用属性直接作为构造函数参数提供。如果需要进一步自定义,可以通过使用平台小部件构建器来实现。请参阅每个小部件的 **增强** 部分。

PlatformWidget

一个根据目标平台渲染 Android 小部件或 Cupertino 小部件的小部件。这些小部件本身不必专门是 Material 或 Cupertino。

return PlatformWidget(
  ios: (_) => Icon(CupertinoIcons.flag),
  android: (_) => Icon(Icons.flag),
);

PlatformText

一个为 Android 渲染大写字母的小部件。iOS 将保持不变。

return PlatformText('Cancel');  

PlatformButton

一个按钮,对于 Android 渲染 `RaisedButton`,对于 iOS 渲染 `CupertinoButton`。

return PlatformButton(
  onPressed: () => print('send'),
  child: PlatformText('Send'),
);

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

return PlatformButton(
  onPressed: () => print('send'),
  child: PlatformText('Send'),
  android: (_) => MaterialRaisedButtonData(...),
  ios: (_) => CupertinoButtonData(...)
);

PlatformIconButton

一个可点击(可触摸)的带图标的按钮。对于 Android 使用 `IconButton`,对于 iOS 使用 `CupertinoButton`。

return PlatformIconButton(
  onPressed: () => print('info pressed'),
  iosIcon: Icon(
    CupertinoIcons.info,
    size: 28.0,
  ),
  androidIcon: Icon(Icons.info)
);

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

Widget infoIconButton() {
  return PlatformIconButton(
    onPressed: () => print('info pressed'),
    iosIcon: Icon(CupertinoIcons.info),
    androidIcon: Icon(Icons.info),
    android: (_) => MaterialIconButtonData(...),
    ios: (_) => CupertinoIconButtonData(...),
  );
}

PlatformScaffold

一个 Scaffold,为每个平台提供正确托管的标题栏(AppBar)和导航栏(底部栏)。对于 Android 使用 `Scaffold`,对于 iOS 使用带底部标签的 `CupertinoTabScaffold` 或不带底部标签的 `CupertinoPageScaffold`。

return PlatformScaffold(
  appBar: PlatformAppBar()
  body: _buildContent(),
  bottomNavBar: PlatformNavBar(),
  iosContentPadding: false
);

请注意,只有当内容被 appBar 遮挡时,才需要使用 `iosContentPadding = true`。

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

return PlatformScaffold(
  appBar: PlatformAppBar()
  body: _buildContent(),
  bottomNavBar: PlatformNavBar(),
  android: (_) => MaterialScaffoldData(...)
  ios: (_) => CupertinoScaffoldData(...);
);

PlatformAppBar

AppBar 是位于顶部的标题栏,包含标题、左侧或右侧按钮。对于 Android 使用 `AppBar`,对于 iOS 使用 `CupertinoNavigationBar`。

return PlatformAppBar(
    title: new Text('Platform Widgets'),
    leading: PlatformIconButton()),
    trailingActions: <Widget>[
      PlatformIconButton(),
    ],
  );

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

return PlatformAppBar(
  title: new Text('Platform Widgets'),
  leading: PlatformIconButton()),
  trailingActions: <Widget>[
    PlatformIconButton(),
  ],
  android: (_) => MaterialAppBarData(...),
  ios: (_)=> CupertinoNavigationBarData(...),
);

PlatformNavBar

注意:`hasNotch` 已被移除,以允许该小部件在 Flutter 的开发分支更改后正常工作。要解决此破坏性更改,可以直接使用 Material 的 `BottomAppBar`,或在 Android 构建中将 `PlatformNavBar` 的结果转换为 `BottomAppBar` 并设置 `hasNotch` 属性。否则,请 targeting 版本 0.2.0。

NavBar 放置在页面底部,包含一组通常用于在屏幕之间导航的按钮。实现此小部件需要父小部件管理页面的 `currentIndex` 并设置 `PlatformNavBar.currrentIndex`。对于 Android 使用带 `BottomNavigationBar` 的 `BottomAppBar`,对于 iOS 使用 `CupertinoTabBar`。

return PlatformNavBar(
  currentIndex: _selectedTabIndex,
  itemChanged: (index) => setState(
        () {
          _selectedTabIndex = index;
        },
      ),
  items: [
    BottomNavigationBarItem(),
    BottomNavigationBarItem(),
  ],
);

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

return PlatformNavBar(
  currentIndex: _selectedTabIndex,
  itemChanged: (index) => setState(
        () {
          _selectedTabIndex = index;
        },
      ),
  items: [
    BottomNavigationBarItem(),
    BottomNavigationBarItem(),
  ],
  android: (_) => MaterialNavBarData(...);
  ios: (_) => CupertinoTabBarData(...),
);

PlatformAlertDialog

AlertDialog 将渲染特定于平台的标题/副标题、正文/文本和一组操作按钮。对于 Android 使用 `AlertDialog`,对于 iOS 使用 `CupertinoAlertDialog`。

请注意,需要使用 material 包中的 `showDialog` 来方便地渲染。

android-dialog

ios-dialog

showDialog(
  context: context,
  builder: (_) => PlatformAlertDialog(
    title: Text('Alert'),
    content: Text('Some content'),
    actions: <Widget>[
      PlatformDialogAction(),
      PlatformDialogAction(),
    ],
  ),
);

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

showDialog(
  context: context,
  builder: (_) => PlatformAlertDialog(...);
  ios: (_) => CupertinoAlertDialogData(...),
  android: (_) => MaterialAlertDialogData(...),
)

PlatformDialogAction

DialogAction 小部件用于描述 AlertDialog 上的按钮集。对于 Android 使用 `FlatButton`,对于 iOS 使用 `CupertinoDialogAction`。

PlatformDialogAction(
  child: PlatformText('Cancel'),
  onPressed: () => Navigator.pop(context),
),

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

PlatformDialogAction(
  child: PlatformText('Cancel'),
  onPressed: () => Navigator.pop(context),
  android: (_) => MaterialDialogActionData(...),
  ios: (_) => CupertinoDialogActionData(...),
),

PlatformCircularProgressIndicator

一个圆形进度指示器。对于 Android 使用 `CircularProgressIndicator`,对于 iOS 使用 `CupertinoActivityIndicator`。

return PlatformCircularProgressIndicator();

增强

通过 `WidgetBuilder` 扩展以支持 Android 或 iOS。

return PlatformCircularProgressIndicator(
  android: (_) => MaterialProgressIndicatorData(...),
  ios: (_)=> CupertinoProgressIndicatorData(...),
);

待办事项

  • UI / 单元测试。
  • 代码文档

以下是需要添加的更多平台感知小部件的列表。

更改 / 检查平台

导入 `flutter_platform_widgets` 时,可以检查 `isMaterial` 或 `isCupertino` 来确定将使用哪种样式。这与 `dart:io` 中的 `Platform.isAndroid` 或 `Platform.isIOS` 是独立的。

有关此用法,请参阅示例代码。

已知限制

如果导航项的数量为 4 或更多,最好将其设置为 fixed。

return PlatformNavBar(
   android: (_) => MaterialNavBarData(
      type: BottomNavigationBarType.fixed,
    ),
  • 将 `BottomNavigationBar.fixedColor` 设置为任何值都不会产生影响。

  • 如果使用 Cupertino 小部件,在将 Material 小部件用在 widget tree 的更下方时,可能会出现没有 Material 父级的错误。如果出现这种情况,需要将 `Material` 放置为子小部件。

return PlatformScaffold(
  body: Material(
    color: Colors.white,
    child: _theBodyOfThePageWithMaterialWidgets(),
  );
);

注意:如果不设置 Material 小部件的颜色,背景上可能会出现轻微的灰色。您可能需要显式设置颜色以匹配页面的其余部分。

  • Cupertino 小部件并非在所有情况下都能拾取 Theme。特别是 Text() 小部件需要设置 DefaultTheme,否则所有 Text() 小部件都需要设置其 style 属性。
return DefaultTextStyle(
  style: Theme.of(context).textTheme.body1,
  child: Center(
     child: Column(
       children: <Widget>[
         PlatformText('Text 1'),
         PlatformText('Text 2'),
         PlatformText('Text 3'),
       ],
     ),
   ),
 );

GitHub

https://github.com/aqwert/flutter_platform_widgets