Flutter SliverAppbar в заголовке NestedScrollView не растягивается и не масштабируется, как в CustomScrollView
SliverAppbar будет растягиваться и увеличиваться, если он находится в customScrollView, но не в NestedScrollView. Только тело NestedScrollView имеет BouncingScrollPhysics, как может заголовок NestedScrollView также иметь BouncingScrollPhysics, чтобы он мог растягивать и масштабировать SliverAppBar.
Однако, если я добавляю scrollController в тело / внутренний scrollView, тогда заголовок SliverAppBar растягивается, но затем они становятся двумя отдельными представлениями прокрутки, и заголовок не прокручивается вверх при прокрутке тела. Проверьте запись экрана
@override
Widget build(BuildContext context) {
return Scaffold(
body: DefaultTabController(
length: 3,
child: NestedScrollView(
physics: BouncingScrollPhysics(),
controller: mainScroller,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
stretch: true,
pinned: true,
floating: false,
elevation: 0,
onStretchTrigger: () {
print('stretch');
return;
},
title: isFlexibleSpaceVisible ? null : Text(widget.name),
expandedHeight: containerHeight - kToolbarHeight,
flexibleSpace: FlexibleSpaceBar(
stretchModes: <StretchMode>[
StretchMode.zoomBackground,
StretchMode.blurBackground,
],
collapseMode: CollapseMode.pin,
background: Container(
color: Theme.of(context).canvasColor,
child: Stack(
children: <Widget>[
Container(
height: headerImageHeight,
width: double.infinity,
decoration: BoxDecoration(
color: kBackgroundColor,
image: DecorationImage(
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.black54,
BlendMode.darken,
),
image: NetworkImage(
'https://picsum.photos/seed/${Random().nextInt(100)}/${MediaQuery.of(context).size.width.toInt()}'),
),
),
),
Container(
height: headerSpace,
margin: EdgeInsets.only(
top: headerImageHeight - bringImageUpMargin),
padding: EdgeInsets.only(left: 8, right: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Theme.of(context).canvasColor,
shape: BoxShape.circle),
padding: EdgeInsets.all(6),
child: CircleAvatar(
backgroundColor: kCardColor,
backgroundImage: NetworkImage(
'https://picsum.photos/seed/${Random().nextInt(100)}/200'),
radius: profileImageRadius,
),
),
Expanded(
child: Container(
margin: EdgeInsets.symmetric(
horizontal: 4, vertical: 12),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: <Widget>[
Text(
widget.name,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700),
),
SizedBox(height: 2),
Wrap(
alignment: WrapAlignment.spaceBetween,
children: <Widget>[
Container(
padding: EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: kPrimaryColor,
borderRadius:
BorderRadius.circular(4)),
child: Text(
widget.skill,
style: TextStyle(
fontSize: 12,
color: Colors.white),
),
),
Container(
padding: EdgeInsets.symmetric(
vertical: 2, horizontal: 6),
decoration: BoxDecoration(
color: kCardColor,
borderRadius:
BorderRadius.circular(4)),
child: Text(
'\$${widget.rate} / ${widget.per}',
style: TextStyle(
color: kPrimaryColor,
fontSize: 12),
),
),
],
),
],
),
),
)
],
),
),
],
),
),
),
),
SliverToBoxAdapter(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 22,
height: 18,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: kSecondaryColor,
),
child: Icon(
Icons.star,
color: Colors.white,
size: 14,
)),
SizedBox(
width: 6,
),
Text('Do you recommend ${widget.name} ?'),
],
),
Row(
children: <Widget>[
Expanded(
child: OutlineButton(
highlightedBorderColor: kSecondaryColor,
color: kSecondaryColor,
borderSide: BorderSide(color: kSecondaryColor),
textColor: kSecondaryColor,
onPressed: () => null,
child: Text('NO'),
),
),
SizedBox(
width: 8,
),
Expanded(
child: RaisedButton(
onPressed: () => null,
child: Text('YES'),
),
),
],
)
],
),
),
),
SliverPersistentHeader(
pinned: true,
delegate: SliverProfileTabs(),
)
];
},
body: ProfileTabsView(data: widget),
),
),
);
}
}
1 ответ
Как упоминалось в комментарии, для этого есть открытая ошибка в GitHub .
Причина такого поведения обсуждалась в этой ветке :
Причина, по которой растяжение не происходит, заключается в том, что
_NestedScrollViewCoodinator
в настоящее время отдает приоритет внутренней прокрутке для любой прокрутки от перетаскивания пользователем. Я думаю, мы можем добавить такой флаг,NestedScrollView.stretchHeaderSlivers
, который перевернет это, чтобы отправить прокрутку на внешний прокручиваемый. Эта часть должна быть легкой.В
_NestedScrollViewCoordinator.createOuterBallisticScrollActivity
необходимо будет реорганизовать, поскольку в настоящее время предполагается, что внешняя прокрутка никогда не будет прокручиваться за пределы, что может быть, а может и не быть таким простым.
И они упомянули, что это огромный рефакторинг и подходящих решений пока нет:
Я пробовал это несколько раз и пока не нашел подходящего решения. NestedScrollView основывается на гораздо большем, чем я, на предположении, что внешний вид прокрутки никогда не будет прокручиваться слишком далеко. Я считаю, что это потребует более масштабного рефакторинга / перепроектирования виджета для поддержки, возможно, работы, которую мы сможем запланировать на новый год. На данный момент я больше не буду активно над этим работать. Я пока не назначаю себя на случай, если кто-то еще захочет попытаться решить эту проблему. :)
Поскольку я не могу просмотреть запись с вашего экрана, я просто опубликую примерное представление о том, как выглядит ошибка. Это было взято из ветки выпуска GitHub .
Образец кода:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
theme: ThemeData.dark(),
home: Home(),
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
body: NestedScrollView(
physics: BouncingScrollPhysics(),
headerSliverBuilder: (context, innerScrolled) => <Widget>[
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
sliver: SliverAppBar(
pinned: true,
stretch: true,
title: Text('username'),
expandedHeight: 325,
flexibleSpace: FlexibleSpaceBar(
stretchModes: <StretchMode>[
StretchMode.zoomBackground,
StretchMode.blurBackground,
],
background: Image.network(
'https://i.imgur.com/QCNbOAo.png',
fit: BoxFit.cover)),
bottom: TabBar(
tabs: <Widget>[Text('test1'), Text('test2')])),
)
],
body: TabBarView(children: [
Center(
child: Builder(
builder: (context) => CustomScrollView(
slivers: <Widget>[
SliverOverlapInjector(
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(
context)),
SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
(_, index) => Text('not working'),
childCount: 100),
itemExtent: 25)
],
),
),
),
Center(child: Text('working'))
])),
));
}
}
Выход: