thl 7 år sedan
förälder
incheckning
0301f2b3a9
9 ändrade filer med 458 tillägg och 11 borttagningar
  1. 4 0
      CHANGELOG.md
  2. 14 0
      README.md
  3. 0 0
      example/android/gradlew
  4. 8 2
      example/lib/main.dart
  5. 2 0
      lib/flustars.dart
  6. 13 8
      lib/src/screen_util.dart
  7. 1 0
      lib/src/sp_util.dart
  8. 415 0
      lib/src/ui/my_app_bar.dart
  9. 1 1
      pubspec.yaml

+ 4 - 0
CHANGELOG.md

@@ -1,3 +1,7 @@
+## 0.1.4
+
+* TODO: ScreenUtil update. UI MyAppBar.
+
 ## 0.1.3
 
 * TODO: Health updated.

+ 14 - 0
README.md

@@ -2,6 +2,18 @@
 [![Pub](https://img.shields.io/pub/v/flustars.svg?style=flat-square)](https://pub.dartlang.org/packages/flustars)
 
 ## [flustars] Flutter常用工具类库。主要对第三方库封装,以便于使用。如果你有好的工具类欢迎PR.  
+
+## 更新说明  
+v0.1.4(2018.11.22)  
+ScreenUtil不依赖context获取屏幕数据。  
+
+新增MyAppBar,不需要GlobalKey就能openDrawer。  
+
+## 关于示例
+本项目中不包含示例,所有示例均在[flutter_demos](https://github.com/Sky24n/flutter_demos)项目中。  
+
+另外一个完整项目[flutter_wanandroid](https://github.com/Sky24n/flutter_wanandroid),欢迎体验!
+
 ### [flustars](https://github.com/Sky24n/flustars)  
  1、SpUtil       : SharedPreferences 工具类.  
  2、ScreenUtil   : 获取屏幕宽、高、密度,AppBar高,状态栏高度,屏幕方向.  
@@ -116,3 +128,5 @@ double dx = offset.dy
 
 ```
 
+
+

+ 0 - 0
example/android/gradlew


+ 8 - 2
example/lib/main.dart

@@ -9,6 +9,8 @@ class MyApp extends StatefulWidget {
 }
 
 class _MyAppState extends State<MyApp> {
+  String _userName = '';
+
   @override
   void initState() {
     super.initState();
@@ -20,8 +22,12 @@ class _MyAppState extends State<MyApp> {
     SpUtil spUtil = await SpUtil.getInstance();
     //SpUtil.remove("username");
     print("SpUtil: " + SpUtil.isInitialized().toString());
-    SpUtil.putString("username", "sky224");
+    SpUtil.putString("username", "sky24");
     print("username: " + SpUtil.getString("username").toString());
+    if (!mounted) return;
+    setState(() {
+      _userName = SpUtil.getString("username");
+    });
   }
 
   @override
@@ -32,7 +38,7 @@ class _MyAppState extends State<MyApp> {
           title: const Text('Plugin example app'),
         ),
         body: new Center(
-          child: new Text('Running on: '),
+          child: new Text('username: $_userName'),
         ),
       ),
     );

+ 2 - 0
lib/flustars.dart

@@ -1,5 +1,7 @@
 library flustars;
 
+export 'src/ui/my_app_bar.dart';
+
 export 'src/screen_util.dart';
 export 'src/widget_util.dart';
 export 'src/sp_util.dart';

+ 13 - 8
lib/src/screen_util.dart

@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'dart:ui' as ui show window;
 
 /**
  * @Author: thl
@@ -22,8 +23,12 @@ class ScreenUtil {
     return singleton;
   }
 
-  void init(BuildContext context) {
-    MediaQueryData mediaQuery = MediaQuery.of(context);
+  ScreenUtil() {
+    init();
+  }
+
+  void init() {
+    MediaQueryData mediaQuery = MediaQueryData.fromWindow(ui.window);
     _mediaQueryData = mediaQuery;
     _screenWidth = mediaQuery.size.width;
     _screenHeight = mediaQuery.size.height;
@@ -33,21 +38,21 @@ class ScreenUtil {
   }
 
   ///screen width
-  static double get screenWidth => _screenWidth;
+  double get screenWidth => _screenWidth;
 
   ///screen height
-  static double get screenHeight => _screenHeight;
+  double get screenHeight => _screenHeight;
 
   ///appBar height
-  static double get appBarHeight => _appBarHeight;
+  double get appBarHeight => _appBarHeight;
 
   ///screen density
-  static double get screenDensity => _screenDensity;
+  double get screenDensity => _screenDensity;
 
   ///status bar Height
-  static double get statusBarHeight => _statusBarHeight;
+  double get statusBarHeight => _statusBarHeight;
 
-  static MediaQueryData get mediaQueryData => _mediaQueryData;
+  MediaQueryData get mediaQueryData => _mediaQueryData;
 
   static double getScreenWidth(BuildContext context) {
     MediaQueryData mediaQuery = MediaQuery.of(context);

+ 1 - 0
lib/src/sp_util.dart

@@ -21,6 +21,7 @@ class SpUtil {
       await _lock.synchronized(() async {
         if (_singleton == null) {
           // keep local instance till it is fully initialized.
+          // 保持本地实例直到完全初始化。
           var singleton = SpUtil._();
           await singleton._init();
           _singleton = singleton;

+ 415 - 0
lib/src/ui/my_app_bar.dart

@@ -0,0 +1,415 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+const double _kLeadingWidth =
+    kToolbarHeight; // So the leading button is square.
+
+// Bottom justify the kToolbarHeight child which may overflow the top.
+class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
+  const _ToolbarContainerLayout();
+
+  @override
+  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
+    return constraints.tighten(height: kToolbarHeight);
+  }
+
+  @override
+  Size getSize(BoxConstraints constraints) {
+    return Size(constraints.maxWidth, kToolbarHeight);
+  }
+
+  @override
+  Offset getPositionForChild(Size size, Size childSize) {
+    return Offset(0.0, size.height - childSize.height);
+  }
+
+  @override
+  bool shouldRelayout(_ToolbarContainerLayout oldDelegate) => false;
+}
+
+class MyAppBar extends StatefulWidget implements PreferredSizeWidget {
+  /// Creates a material design app bar.
+  ///
+  /// The arguments [elevation], [primary], [toolbarOpacity], [bottomOpacity]
+  /// and [automaticallyImplyLeading] must not be null.
+  ///
+  /// Typically used in the [Scaffold.appBar] property.
+  MyAppBar({
+    Key key,
+    this.leading,
+    this.automaticallyImplyLeading = true,
+    this.title,
+    this.actions,
+    this.flexibleSpace,
+    this.bottom,
+    this.elevation = 4.0,
+    this.backgroundColor,
+    this.brightness,
+    this.iconTheme,
+    this.textTheme,
+    this.primary = true,
+    this.centerTitle,
+    this.titleSpacing = NavigationToolbar.kMiddleSpacing,
+    this.toolbarOpacity = 1.0,
+    this.bottomOpacity = 1.0,
+  })  : assert(automaticallyImplyLeading != null),
+        assert(elevation != null),
+        assert(primary != null),
+        assert(titleSpacing != null),
+        assert(toolbarOpacity != null),
+        assert(bottomOpacity != null),
+        preferredSize = Size.fromHeight(
+            kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
+        super(key: key);
+
+  /// A widget to display before the [title].
+  ///
+  /// If this is null and [automaticallyImplyLeading] is set to true, the
+  /// [AppBar] will imply an appropriate widget. For example, if the [AppBar] is
+  /// in a [Scaffold] that also has a [Drawer], the [Scaffold] will fill this
+  /// widget with an [IconButton] that opens the drawer (using [Icons.menu]). If
+  /// there's no [Drawer] and the parent [Navigator] can go back, the [AppBar]
+  /// will use a [BackButton] that calls [Navigator.maybePop].
+  final Widget leading;
+
+  /// Controls whether we should try to imply the leading widget if null.
+  ///
+  /// If true and [leading] is null, automatically try to deduce what the leading
+  /// widget should be. If false and [leading] is null, leading space is given to [title].
+  /// If leading widget is not null, this parameter has no effect.
+  final bool automaticallyImplyLeading;
+
+  /// The primary widget displayed in the appbar.
+  ///
+  /// Typically a [Text] widget containing a description of the current contents
+  /// of the app.
+  final Widget title;
+
+  /// Widgets to display after the [title] widget.
+  ///
+  /// Typically these widgets are [IconButton]s representing common operations.
+  /// For less common operations, consider using a [PopupMenuButton] as the
+  /// last action.
+  ///
+  /// ## Sample code
+  ///
+  /// ```dart
+  /// Scaffold(
+  ///   appBar: AppBar(
+  ///     title: Text('Hello World'),
+  ///     actions: <Widget>[
+  ///       IconButton(
+  ///         icon: Icon(Icons.shopping_cart),
+  ///         tooltip: 'Open shopping cart',
+  ///         onPressed: () {
+  ///           // ...
+  ///         },
+  ///       ),
+  ///     ],
+  ///   ),
+  /// )
+  /// ```
+  final List<Widget> actions;
+
+  /// This widget is stacked behind the toolbar and the tabbar. It's height will
+  /// be the same as the app bar's overall height.
+  ///
+  /// A flexible space isn't actually flexible unless the [AppBar]'s container
+  /// changes the [AppBar]'s size. A [SliverAppBar] in a [CustomScrollView]
+  /// changes the [AppBar]'s height when scrolled.
+  ///
+  /// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
+  final Widget flexibleSpace;
+
+  /// This widget appears across the bottom of the app bar.
+  ///
+  /// Typically a [TabBar]. Only widgets that implement [PreferredSizeWidget] can
+  /// be used at the bottom of an app bar.
+  ///
+  /// See also:
+  ///
+  ///  * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
+  final PreferredSizeWidget bottom;
+
+  /// The z-coordinate at which to place this app bar. This controls the size of
+  /// the shadow below the app bar.
+  ///
+  /// Defaults to 4, the appropriate elevation for app bars.
+  final double elevation;
+
+  /// The color to use for the app bar's material. Typically this should be set
+  /// along with [brightness], [iconTheme], [textTheme].
+  ///
+  /// Defaults to [ThemeData.primaryColor].
+  final Color backgroundColor;
+
+  /// The brightness of the app bar's material. Typically this is set along
+  /// with [backgroundColor], [iconTheme], [textTheme].
+  ///
+  /// Defaults to [ThemeData.primaryColorBrightness].
+  final Brightness brightness;
+
+  /// The color, opacity, and size to use for app bar icons. Typically this
+  /// is set along with [backgroundColor], [brightness], [textTheme].
+  ///
+  /// Defaults to [ThemeData.primaryIconTheme].
+  final IconThemeData iconTheme;
+
+  /// The typographic styles to use for text in the app bar. Typically this is
+  /// set along with [brightness] [backgroundColor], [iconTheme].
+  ///
+  /// Defaults to [ThemeData.primaryTextTheme].
+  final TextTheme textTheme;
+
+  /// Whether this app bar is being displayed at the top of the screen.
+  ///
+  /// If true, the appbar's toolbar elements and [bottom] widget will be
+  /// padded on top by the height of the system status bar. The layout
+  /// of the [flexibleSpace] is not affected by the [primary] property.
+  final bool primary;
+
+  /// Whether the title should be centered.
+  ///
+  /// Defaults to being adapted to the current [TargetPlatform].
+  final bool centerTitle;
+
+  /// The spacing around [title] content on the horizontal axis. This spacing is
+  /// applied even if there is no [leading] content or [actions]. If you want
+  /// [title] to take all the space available, set this value to 0.0.
+  ///
+  /// Defaults to [NavigationToolbar.kMiddleSpacing].
+  final double titleSpacing;
+
+  /// How opaque the toolbar part of the app bar is.
+  ///
+  /// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent.
+  ///
+  /// Typically, this value is not changed from its default value (1.0). It is
+  /// used by [SliverAppBar] to animate the opacity of the toolbar when the app
+  /// bar is scrolled.
+  final double toolbarOpacity;
+
+  /// How opaque the bottom part of the app bar is.
+  ///
+  /// A value of 1.0 is fully opaque, and a value of 0.0 is fully transparent.
+  ///
+  /// Typically, this value is not changed from its default value (1.0). It is
+  /// used by [SliverAppBar] to animate the opacity of the toolbar when the app
+  /// bar is scrolled.
+  final double bottomOpacity;
+
+  /// A size whose height is the sum of [kToolbarHeight] and the [bottom] widget's
+  /// preferred height.
+  ///
+  /// [Scaffold] uses this this size to set its app bar's height.
+  @override
+  final Size preferredSize;
+
+  bool _getEffectiveCenterTitle(ThemeData themeData) {
+    if (centerTitle != null) return centerTitle;
+    assert(themeData.platform != null);
+    switch (themeData.platform) {
+      case TargetPlatform.android:
+      case TargetPlatform.fuchsia:
+        return false;
+      case TargetPlatform.iOS:
+        return actions == null || actions.length < 2;
+    }
+    return null;
+  }
+
+  @override
+  _MyAppBarState createState() => _MyAppBarState();
+}
+
+class _MyAppBarState extends State<MyAppBar> {
+  void _handleDrawerButton() {
+    Scaffold.of(context).openDrawer();
+  }
+
+  void _handleDrawerButtonEnd() {
+    Scaffold.of(context).openEndDrawer();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    assert(!widget.primary || debugCheckHasMediaQuery(context));
+    assert(debugCheckHasMaterialLocalizations(context));
+    final ThemeData themeData = Theme.of(context);
+    final ScaffoldState scaffold = Scaffold.of(context, nullOk: true);
+    final ModalRoute<dynamic> parentRoute = ModalRoute.of(context);
+
+    final bool hasDrawer = scaffold?.hasDrawer ?? false;
+    final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false;
+    final bool canPop = parentRoute?.canPop ?? false;
+    final bool useCloseButton =
+        parentRoute is PageRoute<dynamic> && parentRoute.fullscreenDialog;
+
+    IconThemeData appBarIconTheme =
+        widget.iconTheme ?? themeData.primaryIconTheme;
+    TextStyle centerStyle =
+        widget.textTheme?.title ?? themeData.primaryTextTheme.title;
+    TextStyle sideStyle =
+        widget.textTheme?.body1 ?? themeData.primaryTextTheme.body1;
+
+    if (widget.toolbarOpacity != 1.0) {
+      final double opacity =
+          const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn)
+              .transform(widget.toolbarOpacity);
+      if (centerStyle?.color != null)
+        centerStyle =
+            centerStyle.copyWith(color: centerStyle.color.withOpacity(opacity));
+      if (sideStyle?.color != null)
+        sideStyle =
+            sideStyle.copyWith(color: sideStyle.color.withOpacity(opacity));
+      appBarIconTheme = appBarIconTheme.copyWith(
+          opacity: opacity * (appBarIconTheme.opacity ?? 1.0));
+    }
+
+    Widget leading = widget.leading;
+    //if (leading == null && widget.automaticallyImplyLeading) {
+    if (widget.automaticallyImplyLeading) {
+      if (hasDrawer) {
+        leading = IconButton(
+          //icon: const Icon(Icons.menu),
+          icon: leading ?? const Icon(Icons.menu),
+          onPressed: _handleDrawerButton,
+          tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
+        );
+      } else {
+        if (canPop)
+          leading = useCloseButton ? const CloseButton() : const BackButton();
+      }
+    }
+    if (leading != null) {
+      leading = ConstrainedBox(
+        constraints: const BoxConstraints.tightFor(width: _kLeadingWidth),
+        child: leading,
+      );
+    }
+
+    Widget title = widget.title;
+    if (title != null) {
+      bool namesRoute;
+      switch (defaultTargetPlatform) {
+        case TargetPlatform.android:
+        case TargetPlatform.fuchsia:
+          namesRoute = true;
+          break;
+        case TargetPlatform.iOS:
+          break;
+      }
+      title = DefaultTextStyle(
+        style: centerStyle,
+        softWrap: false,
+        overflow: TextOverflow.ellipsis,
+        child: Semantics(
+          namesRoute: namesRoute,
+          child: title,
+          header: true,
+        ),
+      );
+    }
+
+    Widget actions;
+    if (widget.actions != null && widget.actions.isNotEmpty) {
+      actions = Row(
+        mainAxisSize: MainAxisSize.min,
+        crossAxisAlignment: CrossAxisAlignment.stretch,
+        children: widget.actions,
+      );
+    } else if (hasEndDrawer) {
+      actions = IconButton(
+        icon: const Icon(Icons.menu),
+        onPressed: _handleDrawerButtonEnd,
+        tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
+      );
+    }
+
+    final Widget toolbar = NavigationToolbar(
+      leading: leading,
+      middle: title,
+      trailing: actions,
+      centerMiddle: widget._getEffectiveCenterTitle(themeData),
+      middleSpacing: widget.titleSpacing,
+    );
+
+    // If the toolbar is allocated less than kToolbarHeight make it
+    // appear to scroll upwards within its shrinking container.
+    Widget appBar = ClipRect(
+      child: CustomSingleChildLayout(
+        delegate: const _ToolbarContainerLayout(),
+        child: IconTheme.merge(
+          data: appBarIconTheme,
+          child: DefaultTextStyle(
+            style: sideStyle,
+            child: toolbar,
+          ),
+        ),
+      ),
+    );
+    if (widget.bottom != null) {
+      appBar = Column(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: <Widget>[
+          Flexible(
+            child: ConstrainedBox(
+              constraints: const BoxConstraints(maxHeight: kToolbarHeight),
+              child: appBar,
+            ),
+          ),
+          widget.bottomOpacity == 1.0
+              ? widget.bottom
+              : Opacity(
+                  opacity:
+                      const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn)
+                          .transform(widget.bottomOpacity),
+                  child: widget.bottom,
+                ),
+        ],
+      );
+    }
+
+    // The padding applies to the toolbar and tabbar, not the flexible space.
+    if (widget.primary) {
+      appBar = SafeArea(
+        top: true,
+        child: appBar,
+      );
+    }
+
+    appBar = Align(
+      alignment: Alignment.topCenter,
+      child: appBar,
+    );
+
+    if (widget.flexibleSpace != null) {
+      appBar = Stack(
+        fit: StackFit.passthrough,
+        children: <Widget>[
+          widget.flexibleSpace,
+          appBar,
+        ],
+      );
+    }
+    final Brightness brightness =
+        widget.brightness ?? themeData.primaryColorBrightness;
+    final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark
+        ? SystemUiOverlayStyle.light
+        : SystemUiOverlayStyle.dark;
+
+    return Semantics(
+      container: true,
+      explicitChildNodes: true,
+      child: AnnotatedRegion<SystemUiOverlayStyle>(
+        value: overlayStyle,
+        child: Material(
+          color: widget.backgroundColor ?? themeData.primaryColor,
+          elevation: widget.elevation,
+          child: appBar,
+        ),
+      ),
+    );
+  }
+}

+ 1 - 1
pubspec.yaml

@@ -1,6 +1,6 @@
 name: flustars
 description: Flutter common utils library. SpUtil, ScreenUtil, WidgetUtil.
-version: 0.1.3
+version: 0.1.4
 author: thl <863764940@qq.com>
 homepage: https://github.com/Sky24n/flustars