万年素人からHackerへの道

万年素人がHackerになれるまで殴り書きするぜ。

  • ・資産運用おすすめ
    10万円は1000円くらい利益
    資産運用ブログ アセマネ
    • ・寄付お願いします
      YENTEN:YYzNPzdsZWqr5THWAdMrKDj7GT8ietDc2W
      BitZenny:ZfpUbVya8MWQkjjGJMjA7P9pPkqaLnwPWH
      c0ban:8KG95GXdEquNpPW8xJAJf7nn5kbimQ5wj1
      Skycoin:KMqcn7x8REwwzMHPi9fV9fbNwdofYAWKRo

    Snackbar改造

    MySnackBar

    // Copyright 2015 The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    
    import 'package:flutter/material.dart';
    import 'package:flutter/rendering.dart';
    import 'package:flutter/widgets.dart';
    
    const double _singleLineVerticalPadding = 14.0;
    
    // TODO(ianh): We should check if the given text and actions are going to fit on
    // one line or not, and if they are, use the single-line layout, and if not, use
    // the multiline layout. See link above.
    
    // TODO(ianh): Implement the Tablet version of snackbar if we're "on a tablet".
    
    const Duration _snackBarTransitionDuration = Duration(milliseconds: 250);
    const Duration _snackBarDisplayDuration = Duration(milliseconds: 4000);
    const Curve _snackBarHeightCurve = Curves.fastOutSlowIn;
    const Curve _snackBarFadeInCurve =
        Interval(0.45, 1.0, curve: Curves.fastOutSlowIn);
    const Curve _snackBarFadeOutCurve =
        Interval(0.72, 1.0, curve: Curves.fastOutSlowIn);
    
    /// A lightweight message with an optional action which briefly displays at the
    /// bottom of the screen.
    ///
    /// To display a snack bar, call `Scaffold.of(context).showSnackBar()`, passing
    /// an instance of [MySnackBar] that describes the message.
    ///
    /// To control how long the [MySnackBar] remains visible, specify a [duration].
    ///
    /// A SnackBar with an action will not time out when TalkBack or VoiceOver are
    /// enabled. This is controlled by [AccessibilityFeatures.accessibleNavigation].
    ///
    /// See also:
    ///
    ///  * [Scaffold.of], to obtain the current [ScaffoldState], which manages the
    ///    display and animation of snack bars.
    ///  * [ScaffoldState.showSnackBar], which displays a [MySnackBar].
    ///  * [ScaffoldState.removeCurrentSnackBar], which abruptly hides the currently
    ///    displayed snack bar, if any, and allows the next to be displayed.
    ///  * [SnackBarAction], which is used to specify an [action] button to show
    ///    on the snack bar.
    ///  * [SnackBarThemeData], to configure the default property values for
    ///    [SnackBar] widgets.
    ///  * <https://material.io/design/components/snackbars.html>
    class MySnackBar extends SnackBar {
      /// Creates a snack bar.
      ///
      /// The [content] argument must be non-null. The [elevation] must be null or
      /// non-negative.
      const MySnackBar({
        Key key,
        @required this.content,
        this.backgroundColor,
        this.elevation,
        this.shape,
        this.behavior,
        this.action,
        this.duration = _snackBarDisplayDuration,
        this.animation,
        this.onVisible,
      })  : assert(elevation == null || elevation >= 0.0),
            assert(content != null),
            assert(duration != null),
            super(key: key, content: content);
    
      /// The primary content of the snack bar.
      ///
      /// Typically a [Text] widget.
      final Widget content;
    
      /// The Snackbar's background color. If not specified it will use
      /// [ThemeData.snackBarTheme.backgroundColor]. If that is not specified
      /// it will default to a dark variation of [ColorScheme.surface] for light
      /// themes, or [ColorScheme.onSurface] for dark themes.
      final Color backgroundColor;
    
      /// The z-coordinate at which to place the snack bar. This controls the size
      /// of the shadow below the snack bar.
      ///
      /// Defines the card's [Material.elevation].
      ///
      /// If this property is null, then [ThemeData.snackBarTheme.elevation] is
      /// used, if that is also null, the default value is 6.0.
      final double elevation;
    
      /// The shape of the snack bar's [Material].
      ///
      /// Defines the snack bar's [Material.shape].
      ///
      /// If this property is null then [ThemeData.snackBarTheme.shape] is used.
      /// If that's null then the shape will depend on the [SnackBarBehavior]. For
      /// [SnackBarBehavior.fixed], no overriding shape is specified, so the
      /// [MySnackBar] is rectangular. For [SnackBarBehavior.floating], it uses a
      /// [RoundedRectangleBorder] with a circular corner radius of 4.0.
      final ShapeBorder shape;
    
      /// This defines the behavior and location of the snack bar.
      ///
      /// Defines where a [MySnackBar] should appear within a [Scaffold] and how its
      /// location should be adjusted when the scaffold also includes a
      /// [FloatingActionButton] or a [BottomNavigationBar]
      ///
      /// If this property is null, then [ThemeData.snackBarTheme.behavior]
      /// is used. If that is null, then the default is [SnackBarBehavior.fixed].
      final SnackBarBehavior behavior;
    
      /// (optional) An action that the user can take based on the snack bar.
      ///
      /// For example, the snack bar might let the user undo the operation that
      /// prompted the snackbar. Snack bars can have at most one action.
      ///
      /// The action should not be "dismiss" or "cancel".
      final SnackBarAction action;
    
      /// The amount of time the snack bar should be displayed.
      ///
      /// Defaults to 4.0s.
      ///
      /// See also:
      ///
      ///  * [ScaffoldState.removeCurrentSnackBar], which abruptly hides the
      ///    currently displayed snack bar, if any, and allows the next to be
      ///    displayed.
      ///  * <https://material.io/design/components/snackbars.html>
      final Duration duration;
    
      /// The animation driving the entrance and exit of the snack bar.
      final Animation<double> animation;
    
      /// Called the first time that the snackbar is visible within a [Scaffold].
      final VoidCallback onVisible;
    
      // API for Scaffold.showSnackBar():
    
      /// Creates an animation controller useful for driving a snack bar's entrance and exit animation.
      static AnimationController createAnimationController(
          {@required TickerProvider vsync}) {
        return AnimationController(
          duration: _snackBarTransitionDuration,
          debugLabel: 'SnackBar',
          vsync: vsync,
        );
      }
    
      /// Creates a copy of this snack bar but with the animation replaced with the given animation.
      ///
      /// If the original snack bar lacks a key, the newly created snack bar will
      /// use the given fallback key.
      MySnackBar withAnimation(Animation<double> newAnimation, {Key fallbackKey}) {
        return MySnackBar(
          key: key ?? fallbackKey,
          content: content,
          backgroundColor: backgroundColor,
          elevation: elevation,
          shape: shape,
          behavior: behavior,
          action: action,
          duration: duration,
          animation: newAnimation,
          onVisible: onVisible,
        );
      }
    
      @override
      State<MySnackBar> createState() => _MySnackBarState();
    }
    
    class _MySnackBarState extends State<MySnackBar> {
      bool _wasVisible = false;
    
      @override
      void initState() {
        super.initState();
        widget.animation.addStatusListener(_onAnimationStatusChanged);
      }
    
      @override
      void didUpdateWidget(MySnackBar oldWidget) {
        if (widget.animation != oldWidget.animation) {
          oldWidget.animation.removeStatusListener(_onAnimationStatusChanged);
          widget.animation.addStatusListener(_onAnimationStatusChanged);
        }
        super.didUpdateWidget(oldWidget);
      }
    
      @override
      void dispose() {
        widget.animation.removeStatusListener(_onAnimationStatusChanged);
        super.dispose();
      }
    
      void _onAnimationStatusChanged(AnimationStatus animationStatus) {
        switch (animationStatus) {
          case AnimationStatus.dismissed:
          case AnimationStatus.forward:
          case AnimationStatus.reverse:
            break;
          case AnimationStatus.completed:
            if (widget.onVisible != null && !_wasVisible) {
              widget.onVisible();
            }
            _wasVisible = true;
        }
      }
    
      @override
      Widget build(BuildContext context) {
        final MediaQueryData mediaQueryData = MediaQuery.of(context);
        assert(widget.animation != null);
        final ThemeData theme = Theme.of(context);
        final ColorScheme colorScheme = theme.colorScheme;
        final SnackBarThemeData snackBarTheme = theme.snackBarTheme;
        final bool isThemeDark = theme.brightness == Brightness.dark;
    
        // SnackBar uses a theme that is the opposite brightness from
        // the surrounding theme.
        final Brightness brightness =
            isThemeDark ? Brightness.light : Brightness.dark;
        final Color themeBackgroundColor = isThemeDark
            ? colorScheme.onSurface
            : Color.alphaBlend(
                colorScheme.onSurface.withOpacity(0.80), colorScheme.surface);
        final ThemeData inverseTheme = ThemeData(
          brightness: brightness,
          backgroundColor: themeBackgroundColor,
          colorScheme: ColorScheme(
            primary: colorScheme.onPrimary,
            primaryVariant: colorScheme.onPrimary,
            // For the button color, the spec says it should be primaryVariant, but for
            // backward compatibility on light themes we are leaving it as secondary.
            secondary:
                isThemeDark ? colorScheme.primaryVariant : colorScheme.secondary,
            secondaryVariant: colorScheme.onSecondary,
            surface: colorScheme.onSurface,
            background: themeBackgroundColor,
            error: colorScheme.onError,
            onPrimary: colorScheme.primary,
            onSecondary: colorScheme.secondary,
            onSurface: colorScheme.surface,
            onBackground: colorScheme.background,
            onError: colorScheme.error,
            brightness: brightness,
          ),
          snackBarTheme: snackBarTheme,
        );
    
        final TextStyle contentTextStyle =
            snackBarTheme.contentTextStyle ?? inverseTheme.textTheme.subhead;
        final SnackBarBehavior snackBarBehavior =
            widget.behavior ?? snackBarTheme.behavior ?? SnackBarBehavior.fixed;
        final bool isFloatingSnackBar =
            snackBarBehavior == SnackBarBehavior.floating;
    //    final double snackBarPadding = isFloatingSnackBar ? 16.0 : 24.0;
        // TODO:
        final double snackBarPadding = 0;
    
        final CurvedAnimation heightAnimation =
            CurvedAnimation(parent: widget.animation, curve: _snackBarHeightCurve);
        final CurvedAnimation fadeInAnimation =
            CurvedAnimation(parent: widget.animation, curve: _snackBarFadeInCurve);
        final CurvedAnimation fadeOutAnimation = CurvedAnimation(
          parent: widget.animation,
          curve: _snackBarFadeOutCurve,
          reverseCurve: const Threshold(0.0),
        );
    
        Widget snackBar = SafeArea(
          top: false,
          bottom: !isFloatingSnackBar,
          child: widget.content,
          /*
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              SizedBox(width: snackBarPadding),
              Expanded(
                child: Container(
                  padding: const EdgeInsets.symmetric(
                      vertical: _singleLineVerticalPadding),
                  child: DefaultTextStyle(
                    style: contentTextStyle,
                    child: widget.content,
                  ),
                ),
              ),
              if (widget.action != null)
                ButtonTheme(
                  textTheme: ButtonTextTheme.accent,
                  minWidth: 64.0,
                  padding: EdgeInsets.symmetric(horizontal: snackBarPadding),
                  padding: EdgeInsets.symmetric(horizontal: 0),
                  child: widget.action,
                )
              else
                SizedBox(width: snackBarPadding),
            ],
          ),
          */
        );
    
    //    final double elevation = widget.elevation ?? snackBarTheme.elevation ?? 6.0;
        final double elevation = 0;
        final Color backgroundColor = widget.backgroundColor ??
            snackBarTheme.backgroundColor ??
            inverseTheme.backgroundColor;
        final ShapeBorder shape = widget.shape ??
            snackBarTheme.shape ??
            (isFloatingSnackBar
                ? RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.0))
                : null);
    
        snackBar = Material(
          shape: shape,
          elevation: elevation,
          color: backgroundColor,
          child: Theme(
            data: inverseTheme,
            child: mediaQueryData.accessibleNavigation
                ? snackBar
                : FadeTransition(
                    opacity: fadeOutAnimation,
                    child: snackBar,
                  ),
          ),
        );
    
        if (isFloatingSnackBar) {
          snackBar = Padding(
            padding: const EdgeInsets.fromLTRB(15.0, 5.0, 15.0, 10.0),
            child: snackBar,
          );
        }
    
        snackBar = Semantics(
          container: true,
          liveRegion: true,
          onDismiss: () {
            Scaffold.of(context)
                .removeCurrentSnackBar(reason: SnackBarClosedReason.dismiss);
          },
          child: Dismissible(
            key: const Key('dismissible'),
            direction: DismissDirection.down,
            resizeDuration: null,
            onDismissed: (DismissDirection direction) {
              Scaffold.of(context)
                  .removeCurrentSnackBar(reason: SnackBarClosedReason.swipe);
            },
            child: snackBar,
          ),
        );
    
        Widget snackBarTransition;
        if (mediaQueryData.accessibleNavigation) {
          snackBarTransition = snackBar;
        } else if (isFloatingSnackBar) {
          snackBarTransition = FadeTransition(
            opacity: fadeInAnimation,
            child: snackBar,
          );
        } else {
          snackBarTransition = AnimatedBuilder(
            animation: heightAnimation,
            builder: (BuildContext context, Widget child) {
              return Align(
                alignment: AlignmentDirectional.topStart,
                heightFactor: heightAnimation.value,
                child: child,
              );
            },
            child: snackBar,
          );
        }
    
        return ClipRect(child: snackBarTransition);
      }
    }
    
    class SnackBarPage extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Center(
          child: RaisedButton(
            onPressed: () {
              final snackBar = MySnackBar(
                content: Container(
                    color: Colors.red,
                    width: double.infinity,
                    height: 100,
                    child: Text('オリジナル')),
    //            action: SnackBarAction(
    //              label: 'close',
    //              onPressed: () {
    //                Scaffold.of(context).removeCurrentSnackBar();
    //              },
    //            ),
                duration: Duration(seconds: 3),
              );
              Scaffold.of(context).showSnackBar(snackBar);
            },
            child: Text('スナックバーを開く'),
          ),
        );
      }
    }

    呼び方