如何使用 NestedScrollView 滚动以在 SliverAppBar 上使用堆栈圆形头像?
Posted
技术标签:
【中文标题】如何使用 NestedScrollView 滚动以在 SliverAppBar 上使用堆栈圆形头像?【英文标题】:How to scroll with NestedScrollView to use stack Circle Avatar over SliverAppBar? 【发布时间】:2022-01-15 00:35:23 【问题描述】:我最近在处理一个Flutter项目,遇到这样的问题。
参见照片 1:这是我的代码:照片和文本应位于 TabBar 小部件和设计中的红色背景(蓝色)之间。
这里你可以看到我的实际代码:
主类
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled)
return <Widget>[
PortfoliosliverAppBar(_pages[_tabController.index].item1),
SliverPersistentHeader(
delegate: SliverPersistentHeaderDelegateImpl(
tabBar: TabBar(
padding: EdgeInsets.only(top: 15.0),
labelColor: Colors.black,
indicatorColor: Colors.black,
indicator: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(18)),
color: Colors.blue),
controller: _tabController,
tabs: _pages
.map<Tab>((Tuple3 page) => Tab(text: page.item1))
.toList(),
),
),
),
];
,
body: Container(
margin: EdgeInsets.only(top: 20.0),
child: TabBarView(
controller: _tabController,
children: _pages.map<Widget>((Tuple3 page) => page.item2).toList(),
),
),
银级
class SliverPersistentHeaderDelegateImpl extends SliverPersistentHeaderDelegate
final TabBar tabBar;
final Color color;
const SliverPersistentHeaderDelegateImpl(
Color color = Colors.transparent,
@required this.tabBar,
) : this.color = color;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent)
return Container(
color: color,
child: tabBar,
);
参见照片 2:这是给定的设计:
my view
the actual UI
非常感谢!
【问题讨论】:
【参考方案1】:请参考以下代码
class NestedScrollWithTabs extends StatefulWidget
const NestedScrollWithTabs(Key key) : super(key: key);
@override
_NestedScrollWithTabsState createState() => _NestedScrollWithTabsState();
class _NestedScrollWithTabsState extends State<NestedScrollWithTabs>
with TickerProviderStateMixin
var animation;
var controller;
@override
Widget build(BuildContext context)
return SafeArea(
child: Scaffold(
body: DefaultTabController(
length: 2,
child: NestedScrollView(
physics: NeverScrollableScrollPhysics(),
headerSliverBuilder: (headerCtx, innnerBoxIsScrolled)
if (innnerBoxIsScrolled)
/* Animation */
controller = AnimationController(
vsync: this,
duration: Duration(
seconds: 1,
),
);
animation = Tween(
begin: 0.0,
end: 1.0,
).animate(controller);
/* Animation */
controller.forward();
return <Widget>[
SliverAppBar(
expandedHeight: ScreenUtil().setHeight(185.0),
floating: false,
pinned: true,
backgroundColor: Colors.white,
automaticallyImplyLeading: false,
titleSpacing: 0.0,
centerTitle: true,
elevation: 0.0,
leadingWidth: 0.0,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
if (innnerBoxIsScrolled != null &&
innnerBoxIsScrolled == true)
FadeTransition(
opacity: animation,
child: Text(
"Title",
style: TextStyle(
color: Colors.black,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
),
],
),
flexibleSpace: FlexibleSpaceBar(
background: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Image.network(
"https://images.pexels.com/photos/10181294/pexels-photo-10181294.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" ??
"",
fit: BoxFit.fitWidth,
height: ScreenUtil().setHeight(126.0),
width: ScreenUtil().screenWidth,
filterQuality: FilterQuality.low,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent loadingProgress)
if (loadingProgress == null) return child;
return Container(
height: ScreenUtil().setHeight(126.0),
width: ScreenUtil().screenWidth,
color: Colors.grey,
);
,
errorBuilder: (context, error, stackTrace)
return SizedBox(
height: ScreenUtil().setHeight(126.0),
width: ScreenUtil().screenWidth,
child: Container(
width: ScreenUtil().screenWidth,
),
);
,
),
Positioned(
top: ScreenUtil().setHeight(92.0),
// left: ScreenUtil().setWidth(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircleAvatar(
backgroundColor: Colors.transparent,
radius: 30.0,
child: ClipRRect(
borderRadius: BorderRadius.circular(
45.0,
),
child: Image.network(
"https://images.pexels.com/photos/10181294/pexels-photo-10181294.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" ??
"",
fit: BoxFit.fill,
height: ScreenUtil().setHeight(72.0),
width: ScreenUtil().screenWidth,
filterQuality: FilterQuality.low,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent loadingProgress)
if (loadingProgress == null)
return child;
return Container(
height:
ScreenUtil().setHeight(72.0),
width: ScreenUtil().screenWidth,
color: Colors.grey,
);
,
errorBuilder:
(context, error, stackTrace)
return SizedBox(
height:
ScreenUtil().setHeight(72.0),
width: ScreenUtil().screenWidth,
child: Container(
width: ScreenUtil().screenWidth,
),
);
,
),
),
),
Text("Name"),
Text("Place"),
],
),
),
],
),
],
),
),
),
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
headerCtx),
sliver: SliverPersistentHeader(
delegate: SliverAppBarDelegate(TabBar(
labelColor: Colors.blue,
unselectedLabelColor: Colors.black,
labelStyle: TextStyle(
fontSize: 15.0,
),
unselectedLabelStyle: TextStyle(
fontSize: 15.0,
),
labelPadding: EdgeInsets.zero,
indicatorColor: Colors.blue,
indicatorPadding: EdgeInsets.zero,
physics: NeverScrollableScrollPhysics(),
tabs: [
Tab(
text: "Tab 1",
),
Tab(
text: "Tab 2",
),
],
)),
pinned: false,
),
),
];
,
body: TabBarView(
children: [
/* Tab 1 */
Container(
color: Colors.white,
child: ListView.builder(
itemCount: 100,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index)
return Padding(
padding: const EdgeInsets.all(4.0),
child: Text("Index value: $index"),
);
,
),
),
/* Tab 2 */
Container(
color: Colors.white,
child: ListView.builder(
itemCount: 10,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index)
return Padding(
padding: const EdgeInsets.all(4.0),
child: Text("Index value of Tab 2: $index"),
);
,
),
),
],
),
),
),
),
);
class SliverAppBarDelegate extends SliverPersistentHeaderDelegate
SliverAppBarDelegate(this.tabBars);
final TabBar tabBars;
@override
double get minExtent => 60.0;
@override
double get maxExtent => 60.0;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent)
// shinkOffsetPerValue.value = shrinkOffset;
return new Container(
color: Colors.white,
child: Column(
children: [
tabBars,
],
),
);
@override
bool shouldRebuild(SliverAppBarDelegate oldDelegate)
return false;
【讨论】:
你能补充一点关于你做了什么以及为什么这样做的信息吗,因为这会很有帮助。以上是关于如何使用 NestedScrollView 滚动以在 SliverAppBar 上使用堆栈圆形头像?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用里面的 ListView 滚动 NestedScrollView?
如何在不使用 NestedScrollView 的情况下滚动 ListView?
滚动 NestedScrollView 时如何获取 recyclerview 的当前项目位置?
无法滚动到 NestedScrollView 内的 RecyclerView 中的项目
LinearLayout 和 NestedScrollView 内的 RecyclerView - 如何滚动到某个位置的项目顶部?