Как правильно настроить вложенную прокрутку с помощью SliverOverlapAbsorber во FlutterIOS

Программируем под IOS
Ответить
Anonymous
 Как правильно настроить вложенную прокрутку с помощью SliverOverlapAbsorber во Flutter

Сообщение Anonymous »

Я создаю экран профиля во Flutter, используя NestedScrollView. У меня уже есть SliverOverlapAbsorber для моего SliverAppBar, но мне нужно добавить еще один для моего TabBar. Из-за динамического контента с разной высотой посередине я не могу использовать SliverOverlapAbsorber в качестве нижнего виджета. Как мне правильно настроить виджет моего профиля, чтобы справиться с этой ситуацией?
Вот мои текущие настройки:

Код: Выделить всё

•   NestedScrollView with SliverAppBar.
•   SliverOverlapAbsorber for the SliverAppBar.
•   Dynamic content in the middle section.
•   Need to add SliverOverlapAbsorber for TabBar without affecting the existing setup.
Будем благодарны за любые рекомендации и примеры!
Мой полный код:

Код: Выделить всё

class SimpleProfile extends StatefulWidget {
const SimpleProfile({
super.key,
});

@override
_SimpleProfileState createState() => _SimpleProfileState();
}

class _SimpleProfileState extends State with SingleTickerProviderStateMixin {
late ScrollController _scrollController;
late TabController _tabController;

@override
void initState() {
_scrollController = ScrollController();
super.initState();
_tabController = TabController(length: 6, vsync: this);
}

@override
void dispose() {
_scrollController.dispose();
_tabController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return DefaultTabController(
length: _tabController.length,
child: Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
_profileAppBar(innerBoxIsScrolled),
_profileMainInfo(),
_tabBarSelector(),
];
},
body: Builder(
builder: (context) =>  _tabBarView(),
),
),
),
);
}

Widget _profileAppBar(bool innerBoxIsScrolled) {
return SliverAppBar(
floating: false,
pinned: true,
stretch: true,
forceElevated: innerBoxIsScrolled,
surfaceTintColor: Colors.white,
expandedHeight: 300,
backgroundColor: Colors.black45,
title: null,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
background: Column(
children: [
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
final bgHeight = constraints.maxHeight * 0.85;
const avatarSize = 104.0;
const borderWidth = 2;
final radius = avatarSize / 2;
final imgSize = (radius - borderWidth) * 2;
return Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: SizedBox(
height: bgHeight,
child: Container(
color: Colors.blue,
),
),
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 8,
offset: const Offset(0, 4),
),
],
),
child: CircleAvatar(
radius: radius,
backgroundColor: Colors.white,
child: ClipOval(
child: Container(
color: Colors.blueAccent,
width: imgSize,
height: imgSize,
),
),
),
),
),
],
);
},
),
),
SizedBox(
height: 20,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
'First and Last Names',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 28, fontWeight: FontWeight.w600),
),
),
],
),
),
);
}

Widget _profileMainInfo() {
return SliverToBoxAdapter(
child: Container(
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//some horizontal list
Container(color: Colors.amber, height: 35),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: //some static height Container
Container(color: Colors.green, height: 75),
),
if (true) ...[
const SizedBox(
height: 20,
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
'Some short/medium long text',
textAlign: TextAlign.justify,
style: TextStyle(
fontSize: 17,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w300,
height: 22 / 17,
letterSpacing: -0.408,
textBaseline: TextBaseline.alphabetic,
),
),
),
],
const SizedBox(
height:  20,
),
],
),
),
);
}

Widget _tabBarSelector() {
return SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
TabBar(
padding: const EdgeInsets.symmetric(horizontal: 12),
controller: _tabController,
tabAlignment: TabAlignment.start,
isScrollable: true,
labelPadding: const EdgeInsets.symmetric(horizontal: 12),
labelColor: Colors.black,
indicatorColor: Colors.black,
unselectedLabelColor: Colors.grey,
tabs: const [
Tab(text: 'tab 1'),
Tab(text: 'tab 2'),
Tab(text: 'tab 3'),
Tab(text: 'tab 4'),
Tab(text: 'tab 5'),
Tab(text: 'tab 6'),
],
),
),
);
}

Widget _tabBarView() {
return TabBarView(
controller: _tabController,
children: List.generate(6, (index) {
return Builder(
builder: (BuildContext context) {
return CustomScrollView(
key: PageStorageKey('SomeWidget$index'),
slivers: [
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: SliverFixedExtentList(
itemExtent: 48.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ListTile(
title: Text('Item $index'),
);
},
childCount: 30,
),
),
),
],
);
},
);
}),
);
}
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._tabBar);

final TabBar _tabBar;

@override
double get minExtent => _tabBar.preferredSize.height + 1;
@override
double get maxExtent => _tabBar.preferredSize.height + 1;

@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Column(
children: [
Container(
color: Colors.white,
child: _tabBar,
),
Divider(
height: 1,
color: Colors.grey.withOpacity(0.2),
thickness: 1,
),
],
);
}

@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}
Каждый раз, когда я переключаю вкладки, содержимое внутренней прокрутки начинается с верхней части экрана под панелью приложения. Мне нужно добавить вставку, чтобы сохранить положение прокрутки.
введите здесь описание изображения
Изображение


Подробнее здесь: https://stackoverflow.com/questions/787 ... in-flutter
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»