mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

A sliver that remains âpinnedâ to the top of the scroll view. Subsequent slivers scroll behind it. Typically the sliver is created as the first item in the list however it can be inserted anywhere and it will always stop at the top of the scroll view. When the scrolling axis is vertical, the PinnedHeaderSliverâs height is defined by its widget child. Multiple PinnedHeaderSlivers will layout one after the other, once they've scrolled to the top. This sliver is preferable to the general purpose SliverPersistentHeader - for its relatively narrow use case - because there's no need to create a [SliverPersistentHeaderDelegate] or to predict the header's size. Here's a [working demo in DartPad](https://dartpad.dev/?id=3b3f24c14fa201f752407a21ca9c9456). https://github.com/flutter/flutter/assets/1377460/943f2e02-8e73-48b7-90be-61168978ff71 Related sliver utility PRs: https://github.com/flutter/flutter/pull/143538, https://github.com/flutter/flutter/pull/143325, https://github.com/flutter/flutter/pull/127340.
130 lines
3.2 KiB
Dart
130 lines
3.2 KiB
Dart
// Copyright 2014 The Flutter 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/material.dart';
|
|
|
|
/// Flutter code sample for [PinnedHeaderSliver].
|
|
|
|
void main() {
|
|
runApp(const PinnedHeaderSliverApp());
|
|
}
|
|
|
|
class PinnedHeaderSliverApp extends StatelessWidget {
|
|
const PinnedHeaderSliverApp({ super.key });
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const MaterialApp(
|
|
home: PinnedHeaderSliverExample(),
|
|
);
|
|
}
|
|
}
|
|
|
|
class PinnedHeaderSliverExample extends StatefulWidget {
|
|
const PinnedHeaderSliverExample({ super.key });
|
|
|
|
@override
|
|
State<PinnedHeaderSliverExample> createState() => _PinnedHeaderSliverExampleState();
|
|
}
|
|
|
|
class _PinnedHeaderSliverExampleState extends State<PinnedHeaderSliverExample> {
|
|
int count = 0;
|
|
late final ScrollController scrollController;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
scrollController = ScrollController();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
scrollController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final ThemeData theme = Theme.of(context);
|
|
final ColorScheme colorScheme = theme.colorScheme;
|
|
|
|
final Widget header = Container(
|
|
color: colorScheme.background,
|
|
padding: const EdgeInsets.all(4),
|
|
child: Material(
|
|
color: colorScheme.primaryContainer,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
side: BorderSide(
|
|
width: 7,
|
|
color: colorScheme.outline,
|
|
),
|
|
),
|
|
child: Container(
|
|
alignment: Alignment.center,
|
|
padding: const EdgeInsets.symmetric(vertical: 48),
|
|
child: Text(
|
|
count.isOdd ? 'Alternative Title\nWith Two Lines' : 'PinnedHeaderSliver',
|
|
style: theme.textTheme.headlineMedium!.copyWith(
|
|
color: colorScheme.onPrimaryContainer,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
return Scaffold(
|
|
body: SafeArea(
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
|
child: CustomScrollView(
|
|
controller: scrollController,
|
|
slivers: <Widget>[
|
|
PinnedHeaderSliver(child: header),
|
|
const ItemList(),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
floatingActionButton: FloatingActionButton(
|
|
onPressed: () {
|
|
setState(() {
|
|
count += 1;
|
|
});
|
|
},
|
|
child: const Icon(Icons.add),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// A placeholder SliverList of 25 items.
|
|
class ItemList extends StatelessWidget {
|
|
const ItemList({
|
|
super.key,
|
|
this.itemCount = 25,
|
|
});
|
|
|
|
final int itemCount;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final ColorScheme colorScheme = Theme.of(context).colorScheme;
|
|
return SliverList(
|
|
delegate: SliverChildBuilderDelegate(
|
|
(BuildContext context, int index) {
|
|
return Card(
|
|
color: colorScheme.onSecondary,
|
|
child: ListTile(
|
|
textColor: colorScheme.secondary,
|
|
title: Text('Item $index'),
|
|
),
|
|
);
|
|
},
|
|
childCount: itemCount,
|
|
),
|
|
);
|
|
}
|
|
}
|