123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- // Copyright 2016 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/foundation.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/widgets.dart';
- /// The part of a material design [AppBar] that expands and collapses.
- ///
- /// Most commonly used in in the [SliverAppBar.flexibleSpace] field, a flexible
- /// space bar expands and contracts as the app scrolls so that the [AppBar]
- /// reaches from the top of the app to the top of the scrolling contents of the
- /// app.
- ///
- /// The widget that sizes the [AppBar] must wrap it in the widget returned by
- /// [FlexibleSpaceBar.createSettings], to convey sizing information down to the
- /// [FlexibleSpaceBar].
- ///
- /// See also:
- ///
- /// * [SliverAppBar], which implements the expanding and contracting.
- /// * [AppBar], which is used by [SliverAppBar].
- /// * <https://material.io/design/components/app-bars-top.html#behavior>
- class MyFlexibleSpaceBar extends StatefulWidget {
- /// Creates a flexible space bar.
- ///
- /// Most commonly used in the [AppBar.flexibleSpace] field.
- const MyFlexibleSpaceBar({
- Key key,
- this.title,
- this.background,
- this.centerTitle,
- this.titlePadding,
- this.collapseMode = CollapseMode.parallax,
- }) : assert(collapseMode != null),
- super(key: key);
- /// The primary contents of the flexible space bar when expanded.
- ///
- /// Typically a [Text] widget.
- final Widget title;
- /// Shown behind the [title] when expanded.
- ///
- /// Typically an [Image] widget with [Image.fit] set to [BoxFit.cover].
- final Widget background;
- /// Whether the title should be centered.
- ///
- /// By default this property is true if the current target platform
- /// is [TargetPlatform.iOS], false otherwise.
- final bool centerTitle;
- /// Collapse effect while scrolling.
- ///
- /// Defaults to [MyCollapseMode.parallax].
- final CollapseMode collapseMode;
- /// Defines how far the [title] is inset from either the widget's
- /// bottom-left or its center.
- ///
- /// Typically this property is used to adjust how far the title is
- /// is inset from the bottom-left and it is specified along with
- /// [centerTitle] false.
- ///
- /// By default the value of this property is
- /// `EdgeInsetsDirectional.only(start: 72, bottom: 16)` if the title is
- /// not centered, `EdgeInsetsDirectional.only(start 0, bottom: 16)` otherwise.
- final EdgeInsetsGeometry titlePadding;
- /// Wraps a widget that contains an [AppBar] to convey sizing information down
- /// to the [FlexibleSpaceBar].
- ///
- /// Used by [Scaffold] and [SliverAppBar].
- ///
- /// `toolbarOpacity` affects how transparent the text within the toolbar
- /// appears. `minExtent` sets the minimum height of the resulting
- /// [FlexibleSpaceBar] when fully collapsed. `maxExtent` sets the maximum
- /// height of the resulting [FlexibleSpaceBar] when fully expanded.
- /// `currentExtent` sets the scale of the [FlexibleSpaceBar.background] and
- /// [FlexibleSpaceBar.title] widgets of [FlexibleSpaceBar] upon
- /// initialization.
- ///
- /// See also:
- ///
- /// * [FlexibleSpaceBarSettings] which creates a settings object that can be
- /// used to specify these settings to a [FlexibleSpaceBar].
- static Widget createSettings({
- double toolbarOpacity,
- double minExtent,
- double maxExtent,
- @required double currentExtent,
- @required Widget child,
- }) {
- assert(currentExtent != null);
- return FlexibleSpaceBarSettings(
- toolbarOpacity: toolbarOpacity ?? 1.0,
- minExtent: minExtent ?? currentExtent,
- maxExtent: maxExtent ?? currentExtent,
- currentExtent: currentExtent,
- child: child,
- );
- }
- @override
- _FlexibleSpaceBarState createState() => _FlexibleSpaceBarState();
- }
- class _FlexibleSpaceBarState extends State<MyFlexibleSpaceBar> {
- bool _getEffectiveCenterTitle(ThemeData theme) {
- if (widget.centerTitle != null)
- return widget.centerTitle;
- assert(theme.platform != null);
- switch (theme.platform) {
- case TargetPlatform.android:
- case TargetPlatform.fuchsia:
- return false;
- case TargetPlatform.iOS:
- return true;
- }
- return null;
- }
- Alignment _getTitleAlignment(bool effectiveCenterTitle) {
- if (effectiveCenterTitle)
- return Alignment.bottomCenter;
- final TextDirection textDirection = Directionality.of(context);
- assert(textDirection != null);
- switch (textDirection) {
- case TextDirection.rtl:
- return Alignment.bottomRight;
- case TextDirection.ltr:
- return Alignment.bottomLeft;
- }
- return null;
- }
- double _getCollapsePadding(double t, FlexibleSpaceBarSettings settings) {
- switch (widget.collapseMode) {
- case CollapseMode.pin:
- return -(settings.maxExtent - settings.currentExtent);
- case CollapseMode.none:
- return 0.0;
- case CollapseMode.parallax:
- final double deltaExtent = settings.maxExtent - settings.minExtent;
- return -Tween<double>(begin: 0.0, end: deltaExtent / 4.0).transform(t);
- }
- return null;
- }
- GlobalKey _key = GlobalKey();
- double _offset = 0;
- @override
- void initState() {
- //监听Widget是否绘制完毕
- WidgetsBinding.instance.addPostFrameCallback((_){
- final RenderBox renderBoxRed = _key.currentContext.findRenderObject();
- _offset = renderBoxRed.size.width / 2;
- });
- super.initState();
- }
- @override
- Widget build(BuildContext context) {
- Size size = MediaQuery.of(context).size;
- final FlexibleSpaceBarSettings settings = context.dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>();
- assert(settings != null, 'A FlexibleSpaceBar must be wrapped in the widget returned by FlexibleSpaceBar.createSettings().');
- final List<Widget> children = <Widget>[];
- final double deltaExtent = settings.maxExtent - settings.minExtent;
- // 0.0 -> Expanded
- // 1.0 -> Collapsed to toolbar
- final double t = (1.0 - (settings.currentExtent - settings.minExtent) / deltaExtent).clamp(0.0, 1.0);
- // background image
- // if (widget.background != null) {
- // final double fadeStart = math.max(0.0, 1.0 - kToolbarHeight / deltaExtent);
- // const double fadeEnd = 1.0;
- // assert(fadeStart <= fadeEnd);
- // final double opacity = 1.0 - Interval(fadeStart, fadeEnd).transform(t);
- // if (opacity > 0.0) {
- children.add(Positioned(
- top: _getCollapsePadding(t, settings),
- left: 0.0,
- right: 0.0,
- height: settings.maxExtent,
- child: Opacity(
- opacity: 1,
- child: widget.background,
- ),
- ));
- // }
- // }
- if (widget.title != null) {
- Widget title;
- switch (defaultTargetPlatform) {
- case TargetPlatform.iOS:
- title = widget.title;
- break;
- case TargetPlatform.fuchsia:
- case TargetPlatform.android:
- title = Semantics(
- namesRoute: true,
- child: widget.title,
- );
- }
- title = Container(
- key: _key,
- child: title,
- );
- final ThemeData theme = Theme.of(context);
- final double opacity = settings.toolbarOpacity;
- if (opacity > 0.0) {
- TextStyle titleStyle = theme.primaryTextTheme.title;
- titleStyle = titleStyle.copyWith(
- color: titleStyle.color.withOpacity(opacity),
- fontWeight: t != 0 ? FontWeight.normal : FontWeight.bold
- );
- final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme);
- final EdgeInsetsGeometry padding = widget.titlePadding ??
- EdgeInsetsDirectional.only(
- start: effectiveCenterTitle ? 0.0 : 72.0,
- bottom: 16.0,
- );
- final double scaleValue = Tween<double>(begin: 1.5, end: 1.0).transform(t);
- double width = (size.width - 32.0) / 2 - _offset;
- final Matrix4 scaleTransform = Matrix4.identity()
- ..scale(scaleValue, scaleValue, 1.0)..translate(t * width, 0.0);
- final Alignment titleAlignment = _getTitleAlignment(false);
- children.add(Container(
- padding: padding,
- child: Transform(
- alignment: titleAlignment,
- transform: scaleTransform,
- child: Align(
- alignment: titleAlignment,
- child: DefaultTextStyle(
- style: titleStyle,
- child: title,
- ),
- ),
- ),
- ));
- }
- }
- return ClipRect(child: Stack(children: children));
- }
- }
|