Unverified Commit b3f32004 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[framework] force flexible space background to rebuild. (#128138)

Fixes https://github.com/flutter/flutter/issues/127836

The flexible scroll bar needs to rebuild even if the child/opacity hasn't changed. Force this with a value key.
parent 1e70c52b
...@@ -245,12 +245,18 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> { ...@@ -245,12 +245,18 @@ class _FlexibleSpaceBarState extends State<FlexibleSpaceBar> {
constraints.maxHeight > height) { constraints.maxHeight > height) {
height = constraints.maxHeight; height = constraints.maxHeight;
} }
final double topPadding = _getCollapsePadding(t, settings);
children.add(Positioned( children.add(Positioned(
top: _getCollapsePadding(t, settings), top: topPadding,
left: 0.0, left: 0.0,
right: 0.0, right: 0.0,
height: height, height: height,
child: Opacity( child: Opacity(
// We need the child widget to repaint, however both the opacity
// and potentially `widget.background` can be constant which won't
// lead to repainting.
// see: https://github.com/flutter/flutter/issues/127836
key: ValueKey<double>(topPadding),
// IOS is relying on this semantics node to correctly traverse // IOS is relying on this semantics node to correctly traverse
// through the app bar when it is collapsed. // through the app bar when it is collapsed.
alwaysIncludeSemantics: true, alwaysIncludeSemantics: true,
......
...@@ -348,7 +348,7 @@ void main() { ...@@ -348,7 +348,7 @@ void main() {
rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 56.0), rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 56.0),
children: <TestSemantics>[ children: <TestSemantics>[
TestSemantics( TestSemantics(
id: 11, id: 18,
rect: const Rect.fromLTRB(0.0, 36.0, 800.0, 92.0), rect: const Rect.fromLTRB(0.0, 36.0, 800.0, 92.0),
label: 'Expanded title', label: 'Expanded title',
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
...@@ -409,8 +409,6 @@ void main() { ...@@ -409,8 +409,6 @@ void main() {
label: 'Item 6', label: 'Item 6',
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
), ),
], ],
), ),
], ],
...@@ -786,6 +784,22 @@ void main() { ...@@ -786,6 +784,22 @@ void main() {
await tester.pumpWidget(buildFrame(TargetPlatform.linux, true)); await tester.pumpWidget(buildFrame(TargetPlatform.linux, true));
expect(getTitleBottomLeft(), const Offset(390.0, 0.0)); expect(getTitleBottomLeft(), const Offset(390.0, 0.0));
}); });
testWidgets('FlexibleSpaceBar rebuilds when scrolling.', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: SubCategoryScreenView(),
));
expect(RebuildTracker.count, 1);
// We drag up to fully collapse the space bar.
for (int i = 0; i < 20; i++) {
await tester.drag(find.byKey(SubCategoryScreenView.scrollKey), const Offset(0, -50.0));
await tester.pumpAndSettle();
}
expect(RebuildTracker.count, greaterThan(1));
});
} }
class TestDelegate extends SliverPersistentHeaderDelegate { class TestDelegate extends SliverPersistentHeaderDelegate {
...@@ -810,3 +824,76 @@ class TestDelegate extends SliverPersistentHeaderDelegate { ...@@ -810,3 +824,76 @@ class TestDelegate extends SliverPersistentHeaderDelegate {
@override @override
bool shouldRebuild(TestDelegate oldDelegate) => false; bool shouldRebuild(TestDelegate oldDelegate) => false;
} }
class RebuildTracker extends StatelessWidget {
const RebuildTracker({super.key});
static int count = 0;
@override
Widget build(BuildContext context) {
count++;
return const SizedBox(width: 100, height: 100);
}
}
class SubCategoryScreenView extends StatefulWidget {
const SubCategoryScreenView({
super.key,
});
static const Key scrollKey = Key('orange box');
@override
State<SubCategoryScreenView> createState() => _SubCategoryScreenViewState();
}
class _SubCategoryScreenViewState extends State<SubCategoryScreenView>
with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Test'),
),
body: CustomScrollView(
key: SubCategoryScreenView.scrollKey,
slivers: <Widget>[
SliverAppBar(
leading: const SizedBox(),
expandedHeight: MediaQuery.of(context).size.width / 1.7,
collapsedHeight: 0,
toolbarHeight: 0,
titleSpacing: 0,
leadingWidth: 0,
flexibleSpace: const FlexibleSpaceBar(
background: AspectRatio(
aspectRatio: 1.7,
child: RebuildTracker(),
),
),
),
const SliverToBoxAdapter(child: SizedBox(height: 12)),
SliverToBoxAdapter(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 300,
itemBuilder: (BuildContext context, int index) {
return Card(
color: Colors.amber,
child: Center(child: Text('$index')),
);
},
),
),
const SliverToBoxAdapter(child: SizedBox(height: 12)),
],
),
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment