底部Tab:使用BottomNavigationBar来实现,很简单。不过多解释,都有注释。
class IndexPage extends StatefulWidget {
@override
_IndexPageState createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
List<BottomNavigationBarItem> tabs = [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
title: Text("首页"),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.search),
title: Text("分类"),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.shopping_cart),
title: Text("购物车"),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.profile_circled),
title: Text("我的"),
),
];
List<Widget> pages = [
HomePage(),
CategoryPage(),
ShoppingCartPage(),
MyPage(),
];
int currentIndex = 0;
PageController _controller = PageController();
@override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
body: PageView(
controller: _controller,
children: pages,
physics: NeverScrollableScrollPhysics(),//禁止页面滚动
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
items: tabs,
type: BottomNavigationBarType.fixed,
onTap: (index) {
_controller.jumpToPage(index);
setState(() {
currentIndex = index;
});
},
),
),
);
}
}
顶部Tab:
body: DefaultTabController(
length: 3,//项的数量
initialIndex: 0,//默认选择第一项
child: Column(
children: <Widget>[
Container(
color: Colors.lightBlue,
child: AspectRatio(
aspectRatio: 8.0,
child: TabBar(
// isScrollable: true,//项少的话,无需滚动(自动均分屏幕宽度),多的话,设为true
indicatorColor: Colors.red,
indicatorWeight: 2,
unselectedLabelColor: Colors.white,
labelColor: Colors.red,
tabs: [
Tab(
text: "科技",
),
Tab(
text: "汽车",
),
Tab(
text: "金融",
),
],
),
),
),
Expanded(
child: TabBarView(
children: [
TechFragment(),
CarFragment(),
FinanceFragment(),
],
),
)
],
),
),
——————————————————————————————————————————————————————
有些需求会要求实现某部分布局滑到顶部后吸顶悬浮,可以是一个tabbar,也可以是一个别的组件,但是目的都是让其吸顶悬浮在那,示例代码如下:
class MyScoreFragment extends StatefulWidget {
@override
_MyScoreFragmentState createState() => _MyScoreFragmentState();
}
class _MyScoreFragmentState extends State<MyScoreFragment>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
return Scaffold(
body: ScrollConfiguration(
behavior: MyBehavior(),
child: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
_header(),
_stickyHeader(),
];
},
body: _listData(),
),
),
);
}
@override
void initState() {
super.initState();
}
@override
bool get wantKeepAlive => true;
}
//可折叠头
Widget _header() {
return SliverAppBar(
backgroundColor: Colors.white,
automaticallyImplyLeading: false,
expandedHeight: 120,
flexibleSpace: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("images/center_11.png", width: 40, height: 40),
Container(
margin: EdgeInsets.only(top: 10),
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "总积分:",
style: TextStyle(
color: Color.fromRGBO(135, 135, 135, 1),
fontSize: 14,
),
),
TextSpan(
text: totalScore,
style: TextStyle(
color: Color.fromRGBO(255, 153, 0, 1),
fontSize: 14,
),
),
],
),
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "可兑换积分:",
style: TextStyle(
color: Color.fromRGBO(135, 135, 135, 1),
fontSize: 14,
),
),
TextSpan(
text: canExchangeScore,
style: TextStyle(
color: Color.fromRGBO(135, 135, 135, 1),
fontSize: 14,
),
),
],
),
),
),
],
),
);
}
//粘性头
Widget _stickyHeader() {
return SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
Container(
height: 40,
color: Colors.lightBlue,
child: Row(
children: <Widget>[
Expanded(
child: Container(
alignment: Alignment(0, 0),
child: Text(
"标题",
style: TextStyle(color: Colors.white),
),
),
),
Expanded(
child: Container(
alignment: Alignment(0, 0),
child: Text(
"观看形式",
style: TextStyle(color: Colors.white),
),
),
),
],
),
),
),
);
}
//列表布局
Widget _listData() {
return Container(
child: ListView.builder(
itemCount: _list.length,
itemBuilder: (context, index) {
return _item(_list[index]);
},
),
);
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate(this._container);
final Container _container;
@override
double get minExtent => 40;
@override
double get maxExtent => 40;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return _container;
}
@override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}