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> {
constraints.maxHeight > height) {
height = constraints.maxHeight;
}
final double topPadding = _getCollapsePadding(t, settings);
children.add(Positioned(
top: _getCollapsePadding(t, settings),
top: topPadding,
left: 0.0,
right: 0.0,
height: height,
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
// through the app bar when it is collapsed.
alwaysIncludeSemantics: true,
......
......@@ -348,7 +348,7 @@ void main() {
rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 56.0),
children: <TestSemantics>[
TestSemantics(
id: 11,
id: 18,
rect: const Rect.fromLTRB(0.0, 36.0, 800.0, 92.0),
label: 'Expanded title',
textDirection: TextDirection.ltr,
......@@ -409,8 +409,6 @@ void main() {
label: 'Item 6',
textDirection: TextDirection.ltr,
),
],
),
],
......@@ -786,6 +784,22 @@ void main() {
await tester.pumpWidget(buildFrame(TargetPlatform.linux, true));
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 {
......@@ -810,3 +824,76 @@ class TestDelegate extends SliverPersistentHeaderDelegate {
@override
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