I've arrived at this solution using a CustomScrollView with two SliverAppBar appearing one after another (first one containing YouTube logo and second one with the list of ChoiceChip widgets).

This is what you need. The only problem is I couldn't solve setting the height of the app bar. It's too tall compared to the one in YouTube. The ability to set minimumHeight seems like something that's being worked on looking at this PR:
int _selectedIndex = 0;
List<String> chipTitles = [
'Broski',
'Atom',
'Elon Musk',
'Lemonade',
'Ginger',
'Tiger',
'Drama',
'Comedy',
'COVID-19',
'US'
];
SliverAppBar(
pinned: true,
floating: false,
expandedHeight: 50.0,
flexibleSpace: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: chipTitles.length,
separatorBuilder: (context, index) => SizedBox(
width: 10.0,
),
itemBuilder: (context, index) {
return ChoiceChip(
selected: _selectedIndex == index,
label: Text('${chipTitles[index]}'),
onSelected: (selected) {
if (selected) {
setState(() {
_selectedIndex = index;
});
}
},
);
},
),
),
Also including the full StatefulWidget class for a complete example:
class ScrollerDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ScrollerDemoState();
}
class _ScrollerDemoState extends State<ScrollerDemo> {
int _selectedIndex = 0;
List<String> chipTitles = [
'Broski',
'Atom',
'Elon Musk',
'Lemonade',
'Ginger',
'Tiger',
'Drama',
'Comedy',
'COVID-19',
'US'
];
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
// Results in the logo app bar mimicking the one used in the YouTube app.
pinned: false,
floating: true,
expandedHeight: 80.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('CustomScrollView Demo'),
),
),
SliverAppBar(
pinned: true,
floating: false,
expandedHeight: 50.0,
flexibleSpace: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: chipTitles.length,
separatorBuilder: (context, index) => SizedBox(
width: 10.0,
),
itemBuilder: (context, index) {
return ChoiceChip(
selected: _selectedIndex == index,
label: Text('${chipTitles[index]}'),
onSelected: (selected) {
if (selected) {
setState(() {
_selectedIndex = index;
});
}
},
);
},
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('Grid item $index'),
);
},
childCount: 20,
),
),
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 9)],
child: Text('List item $index'),
);
},
childCount: 36,
),
),
],
);
}
}