1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/material.dart';
6
7/// Flutter code sample for [NestedScrollView].
8
9void main() => runApp(const NestedScrollViewExampleApp());
10
11class NestedScrollViewExampleApp extends StatelessWidget {
12 const NestedScrollViewExampleApp({super.key});
13
14 @override
15 Widget build(BuildContext context) {
16 return const MaterialApp(
17 home: NestedScrollViewExample(),
18 );
19 }
20}
21
22class NestedScrollViewExample extends StatelessWidget {
23 const NestedScrollViewExample({super.key});
24
25 @override
26 Widget build(BuildContext context) {
27 final List<String> tabs = <String>['Tab 1', 'Tab 2'];
28 return DefaultTabController(
29 length: tabs.length, // This is the number of tabs.
30 child: Scaffold(
31 body: NestedScrollView(
32 headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
33 // These are the slivers that show up in the "outer" scroll view.
34 return <Widget>[
35 SliverOverlapAbsorber(
36 // This widget takes the overlapping behavior of the SliverAppBar,
37 // and redirects it to the SliverOverlapInjector below. If it is
38 // missing, then it is possible for the nested "inner" scroll view
39 // below to end up under the SliverAppBar even when the inner
40 // scroll view thinks it has not been scrolled.
41 // This is not necessary if the "headerSliverBuilder" only builds
42 // widgets that do not overlap the next sliver.
43 handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
44 sliver: SliverAppBar(
45 title: const Text('Books'), // This is the title in the app bar.
46 pinned: true,
47 expandedHeight: 150.0,
48 // The "forceElevated" property causes the SliverAppBar to show
49 // a shadow. The "innerBoxIsScrolled" parameter is true when the
50 // inner scroll view is scrolled beyond its "zero" point, i.e.
51 // when it appears to be scrolled below the SliverAppBar.
52 // Without this, there are cases where the shadow would appear
53 // or not appear inappropriately, because the SliverAppBar is
54 // not actually aware of the precise position of the inner
55 // scroll views.
56 forceElevated: innerBoxIsScrolled,
57 bottom: TabBar(
58 // These are the widgets to put in each tab in the tab bar.
59 tabs: tabs.map((String name) => Tab(text: name)).toList(),
60 ),
61 ),
62 ),
63 ];
64 },
65 body: TabBarView(
66 // These are the contents of the tab views, below the tabs.
67 children: tabs.map((String name) {
68 return SafeArea(
69 top: false,
70 bottom: false,
71 child: Builder(
72 // This Builder is needed to provide a BuildContext that is
73 // "inside" the NestedScrollView, so that
74 // sliverOverlapAbsorberHandleFor() can find the
75 // NestedScrollView.
76 builder: (BuildContext context) {
77 return CustomScrollView(
78 // The "controller" and "primary" members should be left
79 // unset, so that the NestedScrollView can control this
80 // inner scroll view.
81 // If the "controller" property is set, then this scroll
82 // view will not be associated with the NestedScrollView.
83 // The PageStorageKey should be unique to this ScrollView;
84 // it allows the list to remember its scroll position when
85 // the tab view is not on the screen.
86 key: PageStorageKey<String>(name),
87 slivers: <Widget>[
88 SliverOverlapInjector(
89 // This is the flip side of the SliverOverlapAbsorber
90 // above.
91 handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
92 ),
93 SliverPadding(
94 padding: const EdgeInsets.all(8.0),
95 // In this example, the inner scroll view has
96 // fixed-height list items, hence the use of
97 // SliverFixedExtentList. However, one could use any
98 // sliver widget here, e.g. SliverList or SliverGrid.
99 sliver: SliverFixedExtentList(
100 // The items in this example are fixed to 48 pixels
101 // high. This matches the Material Design spec for
102 // ListTile widgets.
103 itemExtent: 48.0,
104 delegate: SliverChildBuilderDelegate(
105 (BuildContext context, int index) {
106 // This builder is called for each child.
107 // In this example, we just number each list item.
108 return ListTile(
109 title: Text('Item $index'),
110 );
111 },
112 // The childCount of the SliverChildBuilderDelegate
113 // specifies how many children this inner list
114 // has. In this example, each tab has a list of
115 // exactly 30 items, but this is arbitrary.
116 childCount: 30,
117 ),
118 ),
119 ),
120 ],
121 );
122 },
123 ),
124 );
125 }).toList(),
126 ),
127 ),
128 ),
129 );
130 }
131}
132

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com