我的应用程序有一个包含CustomScrollView和一个Container的Stack。 CustomScrollView具有带扩展头(FlexibleSpaceBar)的SliverAppBar。容器的属性取决于FlexibleSpaceBar的扩展程度。
响应用户手动扩展/折叠SliverAppBar的操作,我很难更新Container属性。
我幼稚的方法是在构建SliverAppBar的FlexibleSpaceBar的过程中确定扩展比例(遵循FlexibleSpaceBar.build中的代码),然后使用setState通知Stack的父级。
但这会导致异常“在构建期间调用setState()或markNeedsBuild()”。
使用FlexibleSpaceBar的构件来构建不相关的小部件的正确方法是什么?
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MyDemoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'demo app',
home: MyHome(),
);
}
}
/// Notifies when there has been a change in the expansion or
/// collapsion[!] of the FlexibleSpace in the SliverAppBar
class FlexibleSpaceBarChangeNotification extends Notification {
final double collapsedFraction;
FlexibleSpaceBarChangeNotification({
this.collapsedFraction,
});
}
class MyHome extends StatefulWidget {
@override
_MyHomeState createState() => _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
double _headerCollapsedFraction = 0.5;
@override
Widget build(BuildContext context) {
return NotificationListener<FlexibleSpaceBarChangeNotification>(
onNotification: (FlexibleSpaceBarChangeNotification notification) {
// This notification occurs when the SliverAppBar is expanded/contracted
setState(() {
_headerCollapsedFraction = notification.collapsedFraction;
});
return true;
},
child: Stack(
children: <Widget>[
Material(
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(
title: MyFlexibleSpaceBarTitle(
// The MyFlexibleSpaceBarTitle widget
child: Text('A List of Items'),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate((context, i) =>
ListTile(
title: Text('List tile #$i'),
),
childCount: 50,
),
),
],
),
),
Container(
width: 100.0,
height: _headerCollapsedFraction * 100.0,
color: Colors.pink,
),
],
),
);
}
}
class MyFlexibleSpaceBarTitle extends StatefulWidget {
final Widget child;
MyFlexibleSpaceBarTitle({
this.child,
});
@override
_MyFlexibleSpaceBarTitleState createState() => _MyFlexibleSpaceBarTitleState();
}
class _MyFlexibleSpaceBarTitleState extends State<MyFlexibleSpaceBarTitle> {
@override
Widget build(BuildContext context) {
// Arithmetic mostly derived from FlexibleSpaceBar.build()
final FlexibleSpaceBarSettings settings = context.inheritFromWidgetOfExactType(FlexibleSpaceBarSettings);
assert(settings != null, 'No FlexibleSpaceBarSettings found');
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);
final double fadeStart = max(0.0, 1.0 - kToolbarHeight / deltaExtent);
const double fadeEnd = 1.0;
assert(fadeStart <= fadeEnd);
final double opacity = Interval(fadeStart, fadeEnd).transform(t);
// This is probably wrong ?
FlexibleSpaceBarChangeNotification(collapsedFraction: t)..dispatch(context);
return Opacity(
opacity: opacity,
child: widget.child,
);
}
}