flui 0.9.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 91

English | 简体中文


FLUI

A powerful UI framework for Google Flutter Demo apk

pub package CI Status Documentation GitHub stars GitHub forks GitHub license

Features #

  • A set of high-quality Flutter widgets out of the box
  • Comprehensive usage examples and documentation
  • Fine-grained non-stylized widgets for different types of applications
  • Supports Dark Mode and RTL
  • Dynamic rendering module -- Dynamic

Compatibility #

FLUI has good compatibility on multiple clients, and the framework will be developed based on Flutter Stable Channel.

Currently supports v1.12.13+hotfix.8 and above.

Getting Started #

Setup

dependencies:
  flui: 0.9.0

Then run flutter pub get to download the dependencies.

Usage

After the dependency installation is completed, you can directly import the widget.

import 'package:flui/flui.dart';

// in somewhere
FLAppBarTitle(
    title: 'AppBar',
    subtitle: '(subtitle)',
    layout: FLAppBarTitleLayout.vertical,
    showLoading: true
)

Widgets #

Dynamic #

dynamic-post

FLUI-Dynamic is a dynamic rendering module that supports rendering widgets based on json strings or objects of a specified type. For more introduction and usage, please see Dynamic

Widget buildDynamicWidget() {
    return FLDyContainer(
       jsonObject: $JSON_STRING_OR_OBJECT,
       placeholder: CircularProgressIndicator(
         strokeWidth: 3.0,
         valueColor: AlwaysStoppedAnimation(Theme.of(context).accentColor),
       ),
    );
}

Contributing #

Principles:

  • Branches that submit new widgets should be named 'feature-' + widget name. Fixing issues need to be prefixed with 'bugfix-'
  • The submitted widgets need to be general. If the widget is rare or not sure whether it needs to be added to FLUI, you can raise a issue which starts with [feature] for discussion
  • The API design of the new widget is as standard and readable as possible, following the naming and usage rules of Flutter's official widgets.
  • Please comment above properties and methods how to use it so that I can add to the documentation and examples.
  • Commit messages: prefix with feat | fix | docs | style | refactor | perf | test | workflow | ci | chore | types:.

License #

MIT License

Change Log #

0.9.0 #

  • New module Dynamic released
  • Flutter version upgrade to v1.12.13 + hotfix.8
  • Widget Documentation Added API list
  • FLToast Added disappearing callback
  • FLStaticSectionData Added header style text style setting
  • Added FLSliverPersistentHeaderWidget -- a floating style list header
  • Fix FLCupertinoActionSheet property setting issue #22
  • Fix FLNoticeBar background color setting issue #19
  • Fix FLMarqueeLabel calculation during update issue #18

0.8.0 #

  • Flutter version upgrade to v1.12.13 + hotfix.5
  • Support Dark Mode
  • Support RTL text direction
  • Widget test integration
  • New widget CountStepper
  • FLToast add custom content view
  • FLMarqueeLabel and FLNoticeBar Added delayed scrolling property delay

Breaking changes:

  • prefix and suffix of FLNoticeBar have been changed to prefixBuilder and suffixBuilder so that you can get the BuildContext instance to build the widget.
  • All dart files under 'lib' are migrated to 'lib/src' for dartdevc

0.7.4 #

  • fix some doc issue.

0.7.3 #

  • FLNoticeBar fix null velocity issue.

0.7.2 #

  • FLCupertinoOperationSheet add custom header widget.

0.7.0 #

First version, include 15 categories:

example/lib/main.dart

import 'dart:io';

import 'pages/dycontainer_page.dart';
import 'pages/dyrich_text_page.dart';
import 'pages/dystack_page.dart';
import 'pages/list_page.dart';
import 'pages/persistent_header_page.dart';
import 'pages/dybutton_page.dart';
import 'pages/dyimage_page.dart';
import 'util.dart';
import 'about_page.dart';
import 'pages/action_sheet_page.dart';
import 'pages/avatar_page.dart';
import 'pages/badge_page.dart';
import 'pages/bubble_page.dart';
import 'pages/button_page.dart';
import 'pages/count_stepper_page.dart';
import 'pages/empty_page.dart';
import 'pages/hints_action_empty_page.dart';
import 'pages/hints_empty_page.dart';
import 'home_page.dart';
import 'pages/image_hints_empty_page.dart';
import 'pages/label_page.dart';
import 'pages/app_bar_page.dart';
import 'pages/loading_empty_page.dart';
import 'pages/notice_page.dart';
import 'pages/skeleton_page.dart';
import 'pages/toast_page.dart';
import 'pages/input_page.dart';
import 'pages/static_list_page.dart';
import 'dynamic_page.dart';
import 'pages/dyalign_page.dart';
import 'pages/dylistview_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'pages/dydemo_home_page.dart';
import 'pages/dydemo_detail_page.dart';
import 'style/theme.dart';
import 'package:flui/flui.dart';

void main() {
  runApp(MyApp());
  if (Platform.isAndroid) {
    SystemUiOverlayStyle systemUiOverlayStyle =
    SystemUiOverlayStyle(statusBarColor: Colors.transparent);
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  }
  Util.initialize();
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  FLToastDefaults _defaults = FLToastDefaults();
  bool _userModeLoaded = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    Util.eventBus.on().listen((event) {
      if (event == 'reset') {
        setState(() {
          _defaults = FLToastDefaults();
        });
      } else if (event == 'theme') {
        setState(() {});
      } else if (event == 'themeLoaded') {
        if (!_userModeLoaded) setState(() {});
      } else if (event == 'direction') {
        setState(() {});
      } else {
        setState(() => _defaults = event);
      }
    });
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangePlatformBrightness() {
    if (Util.themeMode == ThemeMode.system) {
      setState(() {});
    }
  }

  bool _isDarkMode() {
    bool isDarkMode;
    final ThemeMode themeMode = Util.themeMode;
    if (themeMode == ThemeMode.light || themeMode == ThemeMode.dark) {
      isDarkMode = themeMode == ThemeMode.dark;
    } else {
      isDarkMode =
          WidgetsBinding.instance.window.platformBrightness == Brightness.dark;
    }
    return isDarkMode;
  }

  void _updateStatusBar() {
    final SystemUiOverlayStyle overlayStyle =
        _isDarkMode() ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark;
    SystemChrome.setSystemUIOverlayStyle(overlayStyle);
  }

  @override
  Widget build(BuildContext context) {
    if (_userModeLoaded == false && Util.preferences != null) {
      _userModeLoaded = true;
    }

    _updateStatusBar();
    final bool isDarkMode = _isDarkMode();
    final ThemeMode themeMode = Util.themeMode;
    final FLToastStyle style =
        isDarkMode ? FLToastStyle.light : FLToastStyle.dark;
    final FLToastDefaults toastDefaults = FLToastDefaults(
        style: style,
        position: _defaults.position,
        textDirection: Util.textDirection);

    return FLToastProvider(
      defaults: toastDefaults,
      child: MaterialApp(
        title: 'FLUI',
        debugShowCheckedModeBanner: false,
        themeMode: themeMode,
        theme: kLightTheme,
        darkTheme: kDarkTheme,
        routes: {
          HomeTab.routeName: (context) => HomeTab(),
          InputPage.routeName: (context) => InputPage(),
          EmptyPage.routeName: (context) => EmptyPage(),
          LoadingEmptyPage.routeName: (context) => LoadingEmptyPage(),
          HintsEmptyPage.routeName: (context) => HintsEmptyPage(),
          HintsActionEmptyPage.routeName: (context) => HintsActionEmptyPage(),
          ImageHintsEmptyPage.routeName: (context) => ImageHintsEmptyPage(),
          BadgePage.routeName: (context) => BadgePage(),
          LabelPage.routeName: (context) => LabelPage(),
          NoticeBarPage.routeName: (context) => NoticeBarPage(),
          SkeletonPage.routeName: (context) => SkeletonPage(),
          ActionSheetPage.routeName: (context) => ActionSheetPage(),
          AppBarPage.routeName: (context) => AppBarPage(),
          StaticListViewPage.routeName: (context) => StaticListViewPage(),
          ButtonPage.routeName: (context) => ButtonPage(),
          ToastPage.routeName: (context) => ToastPage(),
          BubblePage.routeName: (context) => BubblePage(),
          AvatarPage.routeName: (context) => AvatarPage(),
          InputPage.routeName: (context) => InputPage(),
          CountStepperPage.routeName: (context) => CountStepperPage(),
          PersistentHeaderPage.routeName: (context) => PersistentHeaderPage(),
          ListPage.routeName: (context) => ListPage(),
          // dynamic demo pages
          AlignLayoutPage.routeName: (context) => AlignLayoutPage(),
          ContainerEffectPage.routeName: (context) => ContainerEffectPage(),
          DyListPage.routeName: (context) => DyListPage(),
          StackPage.routeName: (context) => StackPage(),
          DyRichTextPage.routeName: (context) => DyRichTextPage(),
          DyButtonPage.routeName: (context) => DyButtonPage(),
          DyImagePage.routeName: (context) => DyImagePage(),
          DyHomeDemo.routeName: (context) => DyHomeDemo(),
          DyDetailDemo.routeName: (context) => DyDetailDemo()
        },
        builder: (BuildContext context, Widget child) {
          return Directionality(
            textDirection: Util.textDirection,
            child: child,
          );
        },
      ),
    );
  }
}

class HomeTab extends StatefulWidget {
  static const String routeName = '/';

  HomeTab({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _HomeTabState createState() => _HomeTabState();
}

class _HomeTabState extends State<HomeTab> {
  int _currentIndex = 0;
  List pages = [HomePage(), DynamicPage(), AboutPage()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        items: <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.apps),
            title: Text('widgets'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.aspect_ratio),
            title: Text('dynamic'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.info_outline),
            title: Text('about'),
          )
        ],
        currentIndex: _currentIndex,
        onTap: (index) => setState(() => _currentIndex = index),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

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


dependencies:
  flui: ^0.9.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:flui/flui.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
85
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
91
Overall:
Weighted score of the above. [more]
91
Learn more about scoring.

We analyzed this package on Mar 27, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6
  • Flutter: 1.12.13+hotfix.8

Health suggestions

Format lib/src/common/tools.dart.

Run flutter format to format lib/src/common/tools.dart.

Format lib/src/dynamic/action/action.dart.

Run flutter format to format lib/src/dynamic/action/action.dart.

Format lib/src/dynamic/units/base_unit.dart.

Run flutter format to format lib/src/dynamic/units/base_unit.dart.

Fix additional 8 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/src/dynamic/units/container_unit.dart (Run flutter format to format lib/src/dynamic/units/container_unit.dart.)
  • lib/src/dynamic/units/micro_unit.dart (Run flutter format to format lib/src/dynamic/units/micro_unit.dart.)
  • lib/src/dynamic/units/unit_constant.dart (Run flutter format to format lib/src/dynamic/units/unit_constant.dart.)
  • lib/src/dynamic/units/unit_model.dart (Run flutter format to format lib/src/dynamic/units/unit_model.dart.)
  • lib/src/dynamic/util/logger.dart (Run flutter format to format lib/src/dynamic/util/logger.dart.)
  • lib/src/widgets/action_sheet.dart (Run flutter format to format lib/src/widgets/action_sheet.dart.)
  • lib/src/widgets/notice_bar.dart (Run flutter format to format lib/src/widgets/notice_bar.dart.)
  • lib/src/widgets/static_list.dart (Run flutter format to format lib/src/widgets/static_list.dart.)

Maintenance suggestions

The package description is too short. (-9 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.6.0 <3.0.0
flutter 0.0.0
json_annotation ^3.0.1 3.0.1
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
build_runner ^1.7.3
flutter_test
json_serializable ^3.2.5
mockito ^4.1.1