[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.
This commit is contained in:
parent
1e70c52b4e
commit
b3f32004d4
@ -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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user