From b7a49c4afed5e5b884260505c20d8dba1c2632de Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 18 Jul 2019 10:37:08 -0700 Subject: [PATCH] fix sliver fixed pinned appbar (#36333) --- .../rendering/sliver_persistent_header.dart | 2 +- .../slivers_appbar_floating_pinned_test.dart | 232 ++++++++++++++++++ 2 files changed, 233 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/rendering/sliver_persistent_header.dart b/packages/flutter/lib/src/rendering/sliver_persistent_header.dart index 169b98c7a4..6a5ae4228f 100644 --- a/packages/flutter/lib/src/rendering/sliver_persistent_header.dart +++ b/packages/flutter/lib/src/rendering/sliver_persistent_header.dart @@ -476,8 +476,8 @@ abstract class RenderSliverFloatingPersistentHeader extends RenderSliverPersiste } else { _effectiveScrollOffset = constraints.scrollOffset; } + excludeFromSemanticsScrolling = _effectiveScrollOffset <= constraints.scrollOffset; final bool overlapsContent = _effectiveScrollOffset < constraints.scrollOffset; - excludeFromSemanticsScrolling = overlapsContent; layoutChild(_effectiveScrollOffset, maxExtent, overlapsContent: overlapsContent); _childPosition = updateGeometry(); _lastActualScrollOffset = constraints.scrollOffset; diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart index 84e2e265c5..cb6bdd3068 100644 --- a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart @@ -6,7 +6,239 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/material.dart'; +import 'semantics_tester.dart'; + void main() { + testWidgets('Sliver appBars - floating and pinned - correct elevation', (WidgetTester tester) async { + await tester.pumpWidget(Localizations( + locale: const Locale('en', 'us'), + delegates: const >[ + DefaultWidgetsLocalizations.delegate, + DefaultMaterialLocalizations.delegate, + ], + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(), + child: CustomScrollView( + slivers: [ + const SliverAppBar( + bottom: PreferredSize( + preferredSize: Size.fromHeight(28), + child: Text('Bottom'), + ), + backgroundColor: Colors.green, + floating: true, + primary: false, + automaticallyImplyLeading: false, + ), + SliverToBoxAdapter(child: Container(color: Colors.yellow, height: 50.0)), + SliverToBoxAdapter(child: Container(color: Colors.red, height: 50.0)), + ], + ), + ), + ), + ), + ); + + final RenderPhysicalModel renderObject = tester.renderObject(find.byType(PhysicalModel)); + expect(renderObject, isNotNull); + expect(renderObject.elevation, 0.0); + }); + + testWidgets('Sliver appbars - floating and pinned - correct semantics', (WidgetTester tester) async { + await tester.pumpWidget( + Localizations( + locale: const Locale('en', 'us'), + delegates: const >[ + DefaultWidgetsLocalizations.delegate, + DefaultMaterialLocalizations.delegate, + ], + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(), + child: CustomScrollView( + slivers: [ + const SliverAppBar( + title: Text('Hello'), + pinned: true, + floating: true, + expandedHeight: 200.0, + ), + SliverFixedExtentList( + itemExtent: 100.0, + delegate: SliverChildBuilderDelegate( + (BuildContext _, int index) { + return Container( + height: 100.0, + color: index % 2 == 0 ? Colors.red : Colors.yellow, + child: Text('Tile $index'), + ); + }, + ), + ), + ], + ), + ), + ), + ), + ); + + final SemanticsTester semantics = SemanticsTester(tester); + + TestSemantics expectedSemantics = TestSemantics.root( + children: [ + TestSemantics.rootChild( + textDirection: TextDirection.ltr, + children: [ + TestSemantics( + children: [ + TestSemantics( + thickness: 0, + children: [ + TestSemantics( + label: 'Hello', + elevation: 0, + flags: [SemanticsFlag.isHeader, SemanticsFlag.namesRoute], + textDirection: TextDirection.ltr, + ), + ], + ), + TestSemantics( + actions: [SemanticsAction.scrollUp], + flags: [SemanticsFlag.hasImplicitScrolling], + scrollIndex: 0, + children: [ + TestSemantics( + label: 'Tile 0', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 1', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 2', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 3', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 4', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + TestSemantics( + label: 'Tile 5', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + TestSemantics( + label: 'Tile 6', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + ], + ) + ], + ), + ], + ), + ], + ); + expect(semantics, hasSemantics(expectedSemantics, ignoreTransform: true, ignoreId: true, ignoreRect: true)); + + await tester.fling(find.text('Tile 2'), const Offset(0, -600), 2000); + await tester.pumpAndSettle(); + + expectedSemantics = TestSemantics.root( + children: [ + TestSemantics.rootChild( + textDirection: TextDirection.ltr, + children: [ + TestSemantics( + children: [ + TestSemantics( + children: [ + TestSemantics( + label: 'Hello', + flags: [SemanticsFlag.isHeader, SemanticsFlag.namesRoute], + textDirection: TextDirection.ltr, + ), + ], + ), + TestSemantics( + actions: [SemanticsAction.scrollUp, SemanticsAction.scrollDown], + flags: [SemanticsFlag.hasImplicitScrolling], + scrollIndex: 10, + children: [ + TestSemantics( + label: 'Tile 7', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + TestSemantics( + label: 'Tile 8', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + TestSemantics( + label: 'Tile 9', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + TestSemantics( + label: 'Tile 10', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 11', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 12', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 13', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 14', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 15', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 16', + textDirection: TextDirection.ltr, + ), + TestSemantics( + label: 'Tile 17', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + TestSemantics( + label: 'Tile 18', + textDirection: TextDirection.ltr, + flags: [SemanticsFlag.isHidden], + ), + ], + ) + ], + ), + ], + ), + ], + ); + expect(semantics, hasSemantics(expectedSemantics, ignoreTransform: true, ignoreId: true, ignoreRect: true)); + }); + testWidgets('Sliver appbars - floating and pinned - second app bar stacks below', (WidgetTester tester) async { final ScrollController controller = ScrollController(); await tester.pumpWidget(