使用底部导航栏BottomNavigationBar,在其PageView中使用ExtendedNestedScrollView(),
其中headerSliverBuilder中使用了固定的SliverAppBar,TabBar,和中间的使用SliverToBoxAdapter展示的信息。
在body中使用的普通的滚动布局,如GridView
然后在GridView中内容较少,或无的情况下,向上滑动折叠不连贯,不顺畅,需要两次拖拽才能滑至最顶处,中间的卡住时,向上向下都无法继续滑动,得松手重新触摸。
经对比,官方的滑动不会卡住。在页面中直接使用也不会有这问题。GridView的内容超过一屏左右也不会有问题。
希望能有解决的方法
BottomNavigationBar 为正常的使用方式:
return Scaffold(
body: PageView.builder(
itemBuilder: (context, index) => pages[index],
controller: pageController,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.black,
unselectedItemColor: Colors.grey,
selectedFontSize: 10.0,
unselectedFontSize: 10.0,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home_rounded),
activeIcon: Icon(Icons.home_rounded),
label: "Home",
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
activeIcon: Icon(Icons.people),
label: "account",
),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
);
ExtendedNestedScrollView:
class TestExtendedNestedScrollView extends StatefulWidget {
const TestExtendedNestedScrollView({Key? key}) : super(key: key);
@override
_TestExtendedNestedScrollViewState createState() => _TestExtendedNestedScrollViewState();
}
class _TestExtendedNestedScrollViewState extends State<TestExtendedNestedScrollView> {
Widget build(BuildContext context) {
final List<String> _tabs = <String>['Tab 1', 'Tab 2'];
return DefaultTabController(
length: _tabs.length, // This is the number of tabs.
child: Scaffold(
body: GlowNotificationWidget(
ExtendedNestedScrollView(
onlyOneScrollInBody: true,
pinnedHeaderSliverHeightBuilder: () {
double statusBarHeight =
MediaQueryData.fromWindow(window).padding.top;
return appBarHeight + 50 + statusBarHeight;
},
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
// These are the slivers that show up in the "outer" scroll view.
return <Widget>[
SliverAppBar(
title: Text("Test"),
automaticallyImplyLeading: false,
expandedHeight: 200,
pinned: true,
),
SliverToBoxAdapter(
child: Column(
children: [
ListTile(
title: Text('Order'),
),
ListTile(
title: Text('Order'),
),
ListTile(
title: Text('Order'),
),
ListTile(
title: Text('Order'),
),
],
),
),
SliverPersistentHeader(
pinned: true,
delegate: NRSliverHeaderDelegate(
backgroundColor: Colors.white,
islucency: false,
child: PreferredSize(
preferredSize: Size(double.maxFinite, 50),
child: TabBar(
padding: EdgeInsets.zero,
tabs: [
Tab(
text: "Test",
),
Tab(
text: "Tessssssssst",
)
],
isScrollable: true,
indicatorColor: Colors.black,
indicatorSize: TabBarIndicatorSize.tab,
labelColor: Colors.black,
labelStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black,
),
unselectedLabelColor: Colors.grey[100],
labelPadding: EdgeInsets.only(left: 20, right: 15),
onTap: (index) {
},
),
),
),
),
];
},
body: TabBarView(
// These are the contents of the tab views, below the tabs.
children: [
TestTabOne(),
TestTabTwo(),
],
),
),
),
),
);
}
}
class NRSliverHeaderDelegate extends SliverPersistentHeaderDelegate {
PreferredSize child; //传入preferredsize组件,因为此组件需要固定高度
bool islucency; //入参 是否更加滑动变化透明度,true,false
Color backgroundColor; //需要设置的背景色
NRSliverHeaderDelegate(
{required this.islucency,
required this.child,
required this.backgroundColor});
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
double mainHeight = maxExtent - shrinkOffset; //动态获取滑动剩余高度
return Column(
children: [
Container(
height: 49,
width: MediaQuery.of(context).size.width,
color: backgroundColor,
child: Opacity(
opacity: islucency == true && mainHeight != maxExtent
? ((mainHeight / maxExtent) * 0.5).clamp(0, 1)
: 1, //根据滑动高度隐藏显示
child: child),
),
Divider(
height: 1,
color: Colors.grey[200],
)
],
);
}
@override
double get maxExtent => this.child.preferredSize.height;
@override
double get minExtent => this.child.preferredSize.height;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}
GridView:
class TestTabTwo extends StatefulWidget {
const TestTabTwo({Key? key}) : super(key: key);
@override
_TestTabTwoState createState() => _TestTabTwoState();
}
class _TestTabTwoState extends State<TestTabTwo> with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
super.build(context);
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 15,
childAspectRatio: 0.5,
),
itemCount: 0,
itemBuilder: (context, index) {
return Container(
color: Colors.green,
width: double.maxFinite,
height: double.maxFinite,
);
},
);
}
@override
bool get wantKeepAlive => true;
}