From c445c0880ccf224a8343a33215a359d13620cb44 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Wed, 7 Jun 2017 15:25:39 -0700 Subject: [PATCH] Don't visit element children of the childless (#10558) --- .../src/widgets/sliver_persistent_header.dart | 3 +- .../material/tabbed_scrollview_warp_test.dart | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 packages/flutter/test/material/tabbed_scrollview_warp_test.dart diff --git a/packages/flutter/lib/src/widgets/sliver_persistent_header.dart b/packages/flutter/lib/src/widgets/sliver_persistent_header.dart index e4e19a35be..6836268398 100644 --- a/packages/flutter/lib/src/widgets/sliver_persistent_header.dart +++ b/packages/flutter/lib/src/widgets/sliver_persistent_header.dart @@ -140,7 +140,8 @@ class _SliverPersistentHeaderElement extends RenderObjectElement { @override void visitChildren(ElementVisitor visitor) { - visitor(child); + if (child != null) + visitor(child); } } diff --git a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart new file mode 100644 index 0000000000..49824231cf --- /dev/null +++ b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart @@ -0,0 +1,82 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/material.dart'; + +// This is a regression test for https://github.com/flutter/flutter/issues/10549 +// which was failing because _SliverPersistentHeaderElement.visitChildren() +// didn't check child != null before visiting its child. + +class MySliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { + @override + double get minExtent => 50.0; + + @override + double get maxExtent => 150.0; + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => const Placeholder(color: Colors.teal); + + @override + bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => false; +} + +class MyHomePage extends StatefulWidget { + @override + _MyHomePageState createState() => new _MyHomePageState(); +} + +class _MyHomePageState extends State with TickerProviderStateMixin { + static const int tabCount = 3; + TabController tabController; + + @override + void initState() { + super.initState(); + tabController = new TabController(initialIndex: 0, length: tabCount, vsync: this); + } + + @override + void dispose() { + tabController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + bottom: new TabBar( + controller: tabController, + tabs: new List.generate(tabCount, (int index) => new Tab(text: 'Tab $index')).toList(), + ), + ), + body: new TabBarView( + controller: tabController, + children: new List.generate(tabCount, (int index) { + return new CustomScrollView( + // The bug only occurs when this key is included + key: new ValueKey('Page $index'), + slivers: [ + new SliverPersistentHeader( + delegate: new MySliverPersistentHeaderDelegate(), + ), + ], + ); + }).toList(), + ), + ); + } +} + +void main() { + testWidgets('Tabbed CustomScrollViews, warp from tab 1 to 3', (WidgetTester tester) async { + await tester.pumpWidget(new MaterialApp(home: new MyHomePage())); + + // should not crash. + await tester.tap(find.text('Tab 2')); + await tester.pumpAndSettle(); + }); +}