flutter_platform_widgets 0.12.0

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 96

Flutter Platform Widgets #

This project is an attempt to see if it is possible to create widgets that are platform aware. Currently in order to render targeted Android or iOS device specific styles, you need to either conditionaly check the platform or create a set of widgets to render differently depending on the running platform.

This package only supports at most the Beta release. Dev or Master channels are not supprted.

Installation #

Pubspec: https://pub.dev/packages/flutter_platform_widgets

Widgets #

These set of widgets allow for rendering based on the target platform using a single cross platform set of widget.

alt text

alt text

Each PlatformWidget provides common properties directly as constructor arguments. If required further customization can be achieved by using the platform widget builder. See the Enhance section of each widget.

PlatformWidget #

A widget that will render either the android widget or cupertino widget based on the target platform. The widgets themselves do not need to be specifically Material or Cupertino.

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

PlatformText #

A widget that will render uppercase for Android. iOS will remain unchanged.

return PlatformText('Cancel');

PlatformSwitch #

A switch widget that will use a Switch for android or a CupertinoSwitch for iOS.

return PlatformSwitch(
  onChanged: (bool value) {},
  value: value,
);

Enhance #

return PlatformSwitch(
  onChanged: (bool value) {},
  value: value,
  android: (_) => MaterialSwitchData(...),
  ios: (_) => CupertinoSwitchData(...)
);

PlatformSlider #

A slider widget that will use a Slider for android or a CupertinoSlider for iOS

return PlatformSlider(
  onChanged: (bool value) {},
  value: value,
);

Enhance #

return PlatformSlider(
  onChanged: (bool value) {},
  value: value,
  android: (_) => MaterialSliderData(...),
  ios: (_) => CupertinoSliderData(...)
);

PlatformTextField #

A text field widget that will use a TextField for android or a CupertinoTextField for iOS.

return PlatformTextField();

Enhance #

return PlatformTextField(
  android: (_) => MaterialTextFieldData(...),
  ios: (_) => CupertinoTextFieldData(...)
);

PlatformButton #

A button that will render a RaisedButton or FlatButton for android or a CupertinoButton for iOS.

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

Enhance #

Extend with WidgetBuilder for android or iOS.

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

Note: For android you can use the FlatButton instead. To do this use the MaterialFlatButtonData on the androidFlat argument.

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

PlatformIconButton #

A clickable (tappable) button with an icon. Uses IconButton for android or CupertinoButton for iOS.

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

Enhance #

Extend with WidgetBuilder for android or iOS.

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

PlatformApp #

A top level widget for the applciation that uses MaterialApp for android or CupertinoApp for iOS.

return PlatformApp(
  title: 'Flutter Demo',
  home: ...
);

Enhance #

Extend with WidgetBuilder for android or iOS.

return PlatformApp(
  home:  ...
  android: (_) => MaterialAppData(...)
  ios: (_) => CupertinoAppData(...)
);

PlatformScaffold #

A Scaffold that provides the correctly hosted header (AppBar) and navigation bar (Bottom Bar) for each platform. Uses Scaffold for android or CupertinoTabScaffold for iOS with bottom tabs or CupertinoPageScaffold for iOS without bottom tabs.

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

Note that the use of iosContentPadding = true is only required if the content is being obstruced behind the appBar. iosContentBottomPadding is used if the content needs to be above the navBar and not go behind it

Enhance #

Extend with WidgetBuilder for android or iOS.

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

Both the android and iOS builders are optional. If not provided the Container placeholder widget will be returned.

PlatformAppBar #

The AppBar is the top Header bar with a title, leftside or rightside buttons. Uses AppBar for android or CupertinoNavigationBar for iOS.

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

In iOS if a solid color header is required and there is a ListView on the page, you would need to add some alpha to the color so that the ListView is not pushed down too far

     appBar: PlatformAppBar(
       title: Text('iOS Colored Header'),
       ios: (_) => CupertinoNavigationBarData(
             // Issue with cupertino where a bar with no transparency
             // will push the list down. Adding some alpha value fixes it (in a hacky way)
             backgroundColor: Colors.lightGreen.withAlpha(254),
           ),
     ),

Enhance #

Extend with WidgetBuilder for android or iOS.

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

PlatformNavBar #

Note: hasNotch has been removed to allow for the widget to work with the change on the development branch of flutter. To work around the breaking change either use the Material BottomAppBar directly or cast the result from PlatformNavBar to BottomAppBar for android builds and set the hasNotch property. Otherwise target version 0.2.0

The NavBar is placed at the bottom of the page with a set of buttons that typically navigate between screens. Implementing this widget requires the parent widget to manage the currentIndex of the page and to set PlatformNavBar.currrentIndex. Uses BottomAppBar with BottomNavigationBar for android or CupertinoTabBar for iOS.

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

Enhance #

Extend with WidgetBuilder for android or iOS.

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

PlatformAlertDialog #

The AlertDialog will render a caption/title, body/text and a set of action buttons specific for the platform. Uses AlertDialog for android or CupertinoAlertDialog for iOS.

Note use showPlatformDialog instead of either showDialog from the Material library or showCupertinoDialog from the Cupertino library.

alt text

alt text

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

Enhance #

Extend with WidgetBuilder for android or iOS.

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

PlatformDialogAction #

The DialogAction widget is used to describe the set of buttons on the AlertDialog. Uses FlatButton for android or CupertinoDialogAction for iOS.

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

Enhance #

Extend with WidgetBuilder for android or iOS.

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

PlatformCircularProgressIndicator #

A circular looking progress indicator. Uses CircularProgressIndicator for android or CupertinoActivityIndicator for iOS.

return PlatformCircularProgressIndicator();

Enhance #

Extend with WidgetBuilder for android or iOS.

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

PlatformPageRoute #

This function can be used within the Navigator to push either the MaterialPageRoute for android or CupertinoPageRoute for iOS.

  Navigator.push(
    context,
    platformPageRoute(
      builder: pageToDisplayBuilder,
    ),
  );

PlatformProvider #

A Provider that provides access to the functions of swicthing platforms which can be accessed from any screen.

Requires to be placed at the root (above MaterialApp, CupertinoApp or PlatformApp).

  return PlatformProvider(
    builder: (BuildContext context) MaterialApp(...)
  );

And to switch platforms...

PlatformProvider.of(context).changeToMaterialPlatform();

or

PlatformProvider.of(context).changeToCupertinoPlatform();

TODO #

  • UI / Unit Tests.
  • Code documentation

Changing / Checking Platform #

When importing flutter_platform_widgets you can check isMaterial or isCupertino to determine what style will be used. This is independent to Platform.isAndroid or Platform.isIOS from 'import 'dart:io'

See the example code for how this is used.

Issues and Feedback #

Please create an issue to provide feedback or an issue.

Acknowledgements #

Inspired by the example given by Swav Kulinski (https://github.com/swavkulinski/flutter-platform-specific-widgets)

[0.12.0] - June 24, 2019

(Flutter version support: v1.5.4-hotfix.2) #

  • Added PlatformProvider so that swicthing platforms can rebuild the tree
  • Added Material Flat button option for PlatformButton (see Readme)
  • Fixed example issue

[0.11.5] - June 23, 2019 (Do not use)

(Flutter version support: v1.6.3) #

  • Added PlatformProvider so that swicthing platforms can rebuild the tree
  • Due to pub.dev supporting only Stable channel, version 0.11.5 is not supported.

[0.11.0] - June 22, 2019 (Do not use)

(Flutter version support: v1.6.3) #

  • Updated all widgets compatible with Flutter v 1.6.3
  • Added Material Flat button option for PlatformButton (see Readme)
  • Fixed example issue
  • Due to pub.dev supporting only Stable channel, version 0.11.0 is not supported.

[0.10.0] - May 12, 2019

(Flutter version support: v1.5.4-hotfix.2) #

  • Fix for PlatformIconButton and added field. Thanks ericmartineau
  • Updated all widgets compatible with Flutter v1.5.4-hotfix.2

[0.9.6] - May 03, 2019

(Flutter version support: v1.1.8) #

  • Added other checks for platforms.
    • Material = Android, Fuchsia, Windows, Linux
    • Cupertino = iOS, MacOS

[0.9.5] - Feb 07, 2019

(Flutter version support: v1.1.8) #

  • Updated all widgets compatible with Flutter v 1.1.8
  • Added CupertnoThemeData to PlatformApp to style iOS apps.
  • If using PlatformScaffold on each page, no need to define Material widget when using Material widgets on the page

[0.9.0] - Jan 30, 2019

(Flutter version support: v1.0.0) #

  • Added PlatformSlider

[0.8.3] - Jan 30, 2019

(Flutter version support: v1.0.0) #

  • Fix for PlatformTextField keyboardType. Thanks furkantektas

[0.8.2] - Jan 29, 2019

(Flutter version support: v1.0.0) #

  • Added iosContentBottomPadding on PlatformScaffold to prevent the content going behind the navBar
  • Optional android / ios builder for PlatformWidget. No need to specify both if only one if required.

[0.8.1] - Jan 20, 2019

(Flutter version support: v1.0.0) #

  • Updated README

[0.8.0] - Jan 19, 2019

(Flutter version support: v1.0.0) #

  • Added PlatformTextField

[0.7.1] - Jan 18, 2019

(Flutter version support: v1.0.0) #

  • Updated the minSDK version
  • Moved example.dart up a level to appear on pubspec example page

[0.7.0] - Jan 18, 2019

(Flutter version support: v1.0.0) #

  • Added PlatformSwitch

[0.6.0] - Jan 17, 2019

(Flutter version support: v1.0.0) #

  • Added PlatformApp. Thanks cmengler
  • Added showPlatformDialog which is required to be used if PlatformApp is used and you need to show dialogs
  • Added platformPageRoute function to pick the right default route for the platform

[0.5.0] - Nov 30, 2018

(Flutter version support: v1.0.0) #

  • Redone the way PlaformScaffold renders Cupertino. Requires fluttter version 0.11+
  • Added iosContentPadding to PlatformScaffold for iOS to push content bown past the navigation (app) bar

[0.4.0] - Oct 27, 2018

(Flutter version support: v0.9.4) #

  • Caught up with latest flutter verison (0.9.4) adding extra widget properties.

[0.3.4] - Oct 11, 2018

  • Fixed herotag issue when setting transitionBetweenRoutes to true

[0.3.3] - Oct 11, 2018

  • Added transitionBetweenRoutes and heroTag as attributes to CupertinoNavigationBarData

[0.3.2] - Oct 09, 2018

  • Fixed issue with AppBar padding

[0.3.1] - Aug 24, 2018

  • Updated environment to support Dart 2

[0.3.0] - Aug 13, 2018

  • Removed hasNotch to be compatible with the flutter develop branch

[0.2.0] - May 16, 2018

  • Added PlatformCircularProgressIndicator

[0.1.1 - 0.1.4]

  • Bug fixes

[0.1.0] - May 11, 2018

  • Inital Release of Platform widgets

example/example.dart

import 'package:flutter/cupertino.dart' show CupertinoIcons, CupertinoThemeData;
import 'package:flutter/material.dart' show ThemeData, Colors, Icons;
import 'package:flutter/widgets.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';

import 'lib/listViewHeaderPage.dart';
import 'lib/listViewPage.dart';
import 'lib/tabbedPage.dart';

void main() => runApp(Main());

class Main extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) => App();
}

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  Widget build(BuildContext context) {
    final themeData = new ThemeData(
      primarySwatch: Colors.purple,
    );

    final cupertinoTheme = new CupertinoThemeData(
      primaryColor: Colors.purple,
    );

    return PlatformProvider(
      builder: (BuildContext context) => PlatformApp(
            title: 'Flutter Platform Widgets',
            android: (_) => new MaterialAppData(theme: themeData),
            ios: (_) => new CupertinoAppData(theme: cupertinoTheme),
            home: LandingPage(),
          ),
    );
  }
}

class LandingPage extends StatefulWidget {
  @override
  LandingPageState createState() => LandingPageState();
}

class LandingPageState extends State<LandingPage> {
  @override
  initState() {
    super.initState();

    textControlller = TextEditingController(text: 'text');
  }

  bool switchValue = false;
  double sliderValue = 0.5;

  TextEditingController textControlller;

  _switchPlatform(BuildContext context) {
    if (isMaterial) {
      PlatformProvider.of(context).changeToCupertinoPlatform();
    } else {
      PlatformProvider.of(context).changeToMaterialPlatform();
    }
  }

  @override
  Widget build(BuildContext context) {
    return PlatformScaffold(
      iosContentPadding: true,
      appBar: PlatformAppBar(
        title: Text('Flutter Platform Widgets'),
      ),
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                  'Primary concept of this package is to use the same widgets to create iOS (Cupertino) or Android (Material) looking apps rather than needing to discover what widgets to use.'),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Text(
                  'This approach is best when both iOS and Android apps follow the same design in layout and navigation, but need to look as close to native styling as possible.'),
            ),
            Divider(),
            SectionHeader(title: '1. Change Platform'),
            PlatformButton(
              child: PlatformText('Switch Platform'),
              onPressed: () => _switchPlatform(context),
            ),
            PlatformWidget(
              android: (_) => Text('Currently showing Material'),
              ios: (_) => Text('Currently showing Cupertino'),
            ),
            Text('Scaffold: PlatformScaffold'),
            Text('AppBar: PlatformAppBar'),
            Divider(),
            SectionHeader(title: '2. Basic Widgets'),
            PlatformText(
              'PlatformText will uppercase for Material only',
              textAlign: TextAlign.center,
            ),
            PlatformButton(
              child: PlatformText('PlatformButton'),
              onPressed: () {},
            ),
            PlatformButton(
              child: PlatformText('Platform Flat Button'),
              onPressed: () {},
              androidFlat: (_) => MaterialFlatButtonData(),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: PlatformIconButton(
                androidIcon: Icon(Icons.home),
                iosIcon: Icon(CupertinoIcons.home),
                onPressed: () {},
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: PlatformSwitch(
                value: switchValue,
                onChanged: (bool value) => setState(() => switchValue = value),
              ),
            ),
            PlatformSlider(
              value: sliderValue,
              onChanged: (double newValue) {
                setState(() {
                  sliderValue = newValue;
                });
              },
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: PlatformTextField(
                controller: textControlller,
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: PlatformCircularProgressIndicator(),
            ),
            Divider(),
            SectionHeader(title: '3. Dialogs'),
            PlatformButton(
              child: PlatformText('Show Dialog'),
              onPressed: () => _showExampleDialog(),
            ),
            Divider(),
            SectionHeader(title: '4. Navigation'),
            PlatformButton(
              child: PlatformText('Open Tabbed Page'),
              onPressed: () => _openPage((_) => new TabbedPage()),
            ),
            Divider(),
            SectionHeader(title: '5. Advanced'),
            PlatformButton(
              child: PlatformText('Page with ListView'),
              onPressed: () => _openPage((_) => new ListViewPage()),
            ),
            PlatformWidget(
              android: (_) => Container(), //this is for iOS only
              ios: (_) => PlatformButton(
                    child: PlatformText('iOS Page with Colored Header'),
                    onPressed: () => _openPage((_) => new ListViewHeaderPage()),
                  ),
            ),
          ],
        ),
      ),
    );
  }

  _openPage(WidgetBuilder pageToDisplayBuilder) {
    Navigator.push(
      context,
      platformPageRoute(
        builder: pageToDisplayBuilder,
      ),
    );
  }

  _showExampleDialog() {
    showPlatformDialog(
      context: context,
      builder: (_) => PlatformAlertDialog(
            title: Text('Alert'),
            content: Text('Some content'),
            actions: <Widget>[
              PlatformDialogAction(
                android: (_) => MaterialDialogActionData(),
                ios: (_) => CupertinoDialogActionData(),
                child: PlatformText('Cancel'),
                onPressed: () => Navigator.pop(context),
              ),
              PlatformDialogAction(
                child: PlatformText('OK'),
                onPressed: () => Navigator.pop(context),
              ),
            ],
          ),
    );
  }
}

class SectionHeader extends StatelessWidget {
  final String title;

  const SectionHeader({
    @required this.title,
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 4.0),
      child: Text(
        title,
        style: TextStyle(fontSize: 18.0),
      ),
    );
  }
}

class Divider extends StatelessWidget {
  const Divider({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 1.0,
      color: new Color(0xff999999),
      margin: const EdgeInsets.symmetric(vertical: 12.0),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  flutter_platform_widgets: ^0.12.0

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
  
Version Uploaded Documentation Archive
0.12.0 Jun 24, 2019 Go to the documentation of flutter_platform_widgets 0.12.0 Download flutter_platform_widgets 0.12.0 archive
0.11.5 Jun 24, 2019 Go to the documentation of flutter_platform_widgets 0.11.5 Download flutter_platform_widgets 0.11.5 archive
0.11.0 Jun 22, 2019 Go to the documentation of flutter_platform_widgets 0.11.0 Download flutter_platform_widgets 0.11.0 archive
0.10.0 May 12, 2019 Go to the documentation of flutter_platform_widgets 0.10.0 Download flutter_platform_widgets 0.10.0 archive
0.9.6 May 3, 2019 Go to the documentation of flutter_platform_widgets 0.9.6 Download flutter_platform_widgets 0.9.6 archive
0.9.5 Feb 6, 2019 Go to the documentation of flutter_platform_widgets 0.9.5 Download flutter_platform_widgets 0.9.5 archive
0.9.0 Jan 30, 2019 Go to the documentation of flutter_platform_widgets 0.9.0 Download flutter_platform_widgets 0.9.0 archive
0.8.3 Jan 30, 2019 Go to the documentation of flutter_platform_widgets 0.8.3 Download flutter_platform_widgets 0.8.3 archive
0.8.2 Jan 29, 2019 Go to the documentation of flutter_platform_widgets 0.8.2 Download flutter_platform_widgets 0.8.2 archive
0.8.1 Jan 20, 2019 Go to the documentation of flutter_platform_widgets 0.8.1 Download flutter_platform_widgets 0.8.1 archive

All 27 versions...

Popularity:
Describes how popular the package is relative to other packages. [more]
94
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
95
Overall:
Weighted score of the above. [more]
96
Learn more about scoring.

We analyzed this package on Jun 25, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.3.2
  • pana: 0.12.18
  • Flutter: 1.5.4-hotfix.2

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health issues and suggestions

Document public APIs. (-0.69 points)

477 out of 482 API elements have no dartdoc comment.Providing good documentation for libraries, classes, functions, and other API elements improves code readability and helps developers find and use your API.

Maintenance issues and suggestions

Support latest dependencies. (-5 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0-dev.9.4 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11
meta 1.1.6 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test