pageview.builder インデックスのタイトルを持つ sliverAppBar で pageview.builder を作成しようとしています。あるページで sliverAppBar を折りたたむと、次のページにスワイプしても折りたたまれたままになることを願っています。
現在、最初のページでスライバーを折りたたむと、次のページにスクロールするとすぐに、拡張された高さに戻ります
ナビゲーション モデル
class NavigationModel {
final String id;
late final String title;
List<String>? buttonNames;
final String navImage;
NavigationModel(
{required this.id,
required this.title,
this.buttonNames,
required this.navImage});
}
List<NavigationModel> navigation = [
NavigationModel(
id: 'A',
title: 'A',
buttonNames: [],
navImage: 'assets/images/beach4.jpg'),
NavigationModel(
id: 'C',
title: 'C',
buttonNames: [],
navImage: 'assets/images/beach4.jpg'),
NavigationModel(
id: 'P',
title: 'P',
buttonNames: [],
navImage: 'assets/images/beach4.jpg'),
NavigationModel(
id: 'V',
title: 'V',
buttonNames: [],
navImage: 'assets/images/beach4.jpg'),
NavigationModel(
id: 'S',
title: 'S',
buttonNames: [],
navImage: 'assets/images/beach4.jpg'),
];
ナビゲーション バナー
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: navigation.length,
itemBuilder: (BuildContext nav, index) {
return Padding(
padding: EdgeInsets.only(bottom: 16),
child: Row(
children: [
Expanded(
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () async {
_animationController.forward(from: 0.0);
stateNotifier.value = await Navigator.of(context).push(
FadePageRoute(
fullscreenDialog: true,
builder: (context) {
return PageView.builder(
controller: PageController(
initialPage: index, keepPage: true),
itemBuilder: (context, position) {
return NavigatedPage(
selectedIndex:
position % navigation.length,
);
});
}),
);
},
child: Hero(
tag: '${navigation[index].id}-img',
child: Image.asset(
'assets/images/beach4.jpg',
fit: BoxFit.cover,
height: 60,
width: MediaQuery.of(context).size.width * 0.95,
)),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Container(
padding: EdgeInsets.only(top: 35, left: 14),
width: 180,
child: Hero(
tag: '${navigation[index].id}-title',
flightShuttleBuilder: (
BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,
) {
return NavigationTitle(
title: navigation[index].title,
viewState:
flightDirection == HeroFlightDirection.push
? ViewState.enlarge
: ViewState.shrink,
isOverflow: true,
smallFontSize: 15.0,
largeFontSize: 32.0,
);
},
child: NavigationTitle(
title: navigation[index].title,
viewState: ViewState.shrunk,
),
)),
),
],
))
],
),
);
},
);
ナビゲーションページ
@override
Widget build(BuildContext context) {
contentSpacing = MediaQuery.of(context).size.width;
return WillPopScope(
onWillPop: () {
Navigator.of(context).pop(true);
return Future.value(false);
},
child: Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
snap: false,
pinned: true,
floating: false,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text(navigation[currentIndex].title),
background: Image.asset(
navigation[currentIndex].navImage,
fit: BoxFit.cover,
),
),
expandedHeight: 230,
backgroundColor: Colors.greenAccent[400],
leading: IconButton(
icon: Icon(Icons.menu),
tooltip: 'Menu',
onPressed: () {
Navigator.pop(context);
},
), //IconButton
actions: <Widget>[
IconButton(
icon: Icon(Icons.comment),
tooltip: 'Comment Icon',
onPressed: () {},
), //IconButton
IconButton(
icon: Icon(Icons.settings),
tooltip: 'Setting Icon',
onPressed: () {},
),
],
),
];
},
body: Column(
children: [
Container(
height: 200,
child: ListView.builder(
itemCount: navigation[currentIndex].buttonNames!.length,
itemBuilder: (
BuildContext ctx,
int index,
) {
return Column(
children: [
ElevatedButton(
onPressed: () async {
await Navigator.pushNamed(
ctx,
navigation[currentIndex]
.buttonNames![index]
.toString());
},
child: Text(navigation[currentIndex]
.buttonNames![index]
.toString()),
),
],
);
},
),
),
],
),
)));
}
}
class NavContent extends StatelessWidget {
final bool isHero;
final double dx;
final double initialDx;
final NavigationModel destination;
const NavContent({
Key? key,
required this.destination,
this.isHero = false,
this.dx = 0.0,
this.initialDx = 0.0,
}) : super(key: key);
@override
Widget build(BuildContext context) {
double maxOffset = MediaQuery.of(context).size.width;
return ListView(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 380.0,
),
child: Stack(
clipBehavior: Clip.none,
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: isHero
? Hero(
tag: 'PocketPK',
child: Header(
viewState: ViewState.shrunk,
),
)
: Container(),
),
Positioned(
top: 50.0,
left: dx * 1.5,
child: Opacity(
opacity: isHero ? 1.0 - (dx.abs() / maxOffset) : 1.0,
child: Hero(
tag: isHero ? '${destination.id}-img' : 'img',
child: Image.asset(
destination.navImage,
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width * 0.9,
height: 300.0,
),
),
),
),
Positioned(
top: 280.0,
left: dx * 1.4 + 16.0,
child: FractionalTranslation(
translation: Offset(0.0, 0.5),
child: Opacity(
opacity: isHero ? 1.0 - (dx.abs() / maxOffset) : 1.0,
child: Hero(
tag: isHero ? '${destination.id}-title' : 'title',
child: NavigationTitle(
title: destination.title,
viewState: ViewState.enlarged,
),
),
),
),
),
],
),
),
],
);
ゴール
https://twitter.com/i/status/1001705364587466752
https://github.com/Ramotion/navigation-toolbar-android/raw/master/Navigation-toolbar.gif