当前位置:   article > 正文

Flutter实战项目-第九篇 吸顶及滚动条嵌套_flutter 嵌套滑动

flutter 嵌套滑动

概要

  • 滚动条嵌套
  • 吸顶
  • CustomScrollView、SliverList

一、滚动条嵌套

现实场景中可能会出现嵌套布局的情况,其实这种场景和吸顶基本是一致,可以采用同样是方法实现上述两种场景。

首先我们可以看下嵌套的效果。

整个页面是一个滚动,白色部分其实是内嵌的滚动。当然我这样看可能和一般的滚动没什么区别。为了更直观的表现嵌套,可以加上吸顶的效果,这样就可以直观的看到嵌套的效果了。

二、完整代码

  1. import 'dart:math';
  2. import 'package:flutter/material.dart';
  3. import './../../component/menu.tab.dart';
  4. class Surprise extends StatefulWidget {
  5. const Surprise({Key? key}) : super(key: key);
  6. static const routeName = '/test3';
  7. @override
  8. State<Surprise> createState() => _SurpriseState();
  9. }
  10. class _SurpriseState extends State<Surprise> {
  11. @override
  12. Widget build(BuildContext context) {
  13. return Scaffold(
  14. appBar: AppBar(
  15. toolbarHeight: 0,
  16. backgroundColor: Colors.white,
  17. elevation: 0,
  18. ),
  19. backgroundColor:const Color(0xFFfafafa),
  20. body:CustomScrollView(
  21. slivers: <Widget>[
  22. _buildBanner(),
  23. _buildStickyBar(),
  24. _buildList(),
  25. ],
  26. )
  27. );
  28. }
  29. Widget _buildBanner() {
  30. return SliverToBoxAdapter(
  31. child:SizedBox(
  32. height: 200,
  33. child:Stack(
  34. children: [
  35. SizedBox(
  36. width: double.infinity,
  37. height: 200,
  38. child: Image.network(
  39. "https://img30.360buyimg.com/img/jfs/t1/92581/29/20454/374562/61de544fE1d5e1e34/f69d41d732f3fe81.jpg",
  40. height: double.infinity,
  41. fit: BoxFit.fill,
  42. ),
  43. ),
  44. Positioned(
  45. bottom: -1,
  46. width: MediaQuery.of(context).size.width,
  47. child: Container(
  48. height: 10,
  49. decoration:const BoxDecoration(
  50. color:Color(0xFFfafafa),
  51. borderRadius: BorderRadius.only(
  52. topLeft: Radius.circular(6),
  53. topRight: Radius.circular(6),
  54. )
  55. ),
  56. )
  57. )
  58. ],
  59. ),
  60. )
  61. );
  62. }
  63. Widget _buildStickyBar() {
  64. return SliverPersistentHeader(
  65. pinned: true, //是否固定在顶部
  66. floating: true,
  67. delegate: _SliverAppBarDelegate(
  68. minHeight: 50, //收起的高度
  69. maxHeight: 50, //展开的最大高度
  70. child: Container(
  71. padding: const EdgeInsets.only(left: 16),
  72. color:const Color(0xFFfafafa),
  73. alignment: Alignment.centerLeft,
  74. child: Row(
  75. children: [
  76. Container(
  77. width: 50,
  78. alignment: Alignment.center,
  79. child: const Text("精选", style: TextStyle(fontSize: 18)),
  80. ),
  81. Expanded(
  82. child:MenuTab(
  83. menuList:const [
  84. {"value":"1","text":"京喜自营"},
  85. {"value":"2","text":"母婴玩具"},
  86. {"value":"3","text":"生活百货"},
  87. {"value":"4","text":"酒水饮料"},
  88. {"value":"5","text":"家清纸品"},
  89. {"value":"6","text":"米面粮油"},
  90. {"value":"7","text":"数码配件"},
  91. {"value":"8","text":"大小家电"},
  92. {"value":"9","text":"服饰鞋靴"},
  93. {"value":"10","text":"美妆个护"},
  94. {"value":"11","text":"休闲零食"},
  95. ],
  96. onPress: (e){
  97. setState(() {
  98. });
  99. },
  100. )
  101. )
  102. ],
  103. ),
  104. )),
  105. );
  106. }
  107. Widget _buildList() {
  108. return SliverList(
  109. delegate: SliverChildBuilderDelegate(
  110. (context, index) {
  111. return Container(
  112. height: 100,
  113. alignment: Alignment.center,
  114. child: Text("$index,Container"),
  115. );
  116. },
  117. childCount:10,
  118. ));
  119. }
  120. }
  121. class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  122. _SliverAppBarDelegate({
  123. required this.minHeight,
  124. required this.maxHeight,
  125. required this.child,
  126. });
  127. final double minHeight;
  128. final double maxHeight;
  129. final Widget child;
  130. @override
  131. double get minExtent => minHeight;
  132. @override
  133. double get maxExtent => max(maxHeight, minHeight);
  134. @override
  135. Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
  136. return SizedBox.expand(child: child);
  137. }
  138. @override
  139. bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
  140. return maxHeight != oldDelegate.maxHeight ||
  141. minHeight != oldDelegate.minHeight ||
  142. child != oldDelegate.child;
  143. }
  144. }
  1. import 'package:flutter/material.dart';
  2. class MenuTab extends StatefulWidget {
  3. final Function? onPress;
  4. final List<Map<String, dynamic>> menuList;
  5. const MenuTab({Key? key,required this.menuList,this.onPress}) : super(key: key);
  6. @override
  7. State<MenuTab> createState() => _MenuTabState();
  8. }
  9. class _MenuTabState extends State<MenuTab> {
  10. final ScrollController _controller = ScrollController();
  11. late String currerValue = "";
  12. final GlobalKey menuTabListKey = GlobalKey();
  13. List<Widget> generateMenuTabList (){
  14. List<Widget> menuTabList = [];
  15. for(var i = 0; i < widget.menuList.length; i++){
  16. menuTabList.add(
  17. InkResponse(
  18. splashColor:Colors.transparent,
  19. splashFactory: NoSplash.splashFactory,
  20. child:Container(
  21. width: 100,
  22. alignment: Alignment.center,
  23. child: Column(
  24. mainAxisAlignment: MainAxisAlignment.center,
  25. children: [
  26. Text(
  27. widget.menuList[i]["text"],
  28. style: TextStyle(
  29. fontWeight: currerValue== widget.menuList[i]["value"] as String?FontWeight.bold:FontWeight.normal,
  30. fontSize: currerValue== widget.menuList[i]["value"] as String?20:18,
  31. color: currerValue== widget.menuList[i]["value"] as String? const Color(0xFFf81818):const Color(0xFF000000)
  32. )
  33. ),
  34. SizedBox(
  35. width: 50,
  36. height: 2,
  37. child: DecoratedBox(
  38. decoration: BoxDecoration(
  39. color: currerValue== widget.menuList[i]["value"] as String?const Color(0xFFf81818):Colors.transparent
  40. ),
  41. )
  42. )
  43. ],
  44. )
  45. ),
  46. onTap: (){
  47. chosenTab(widget.menuList[i],i);
  48. if(widget.onPress!=null){
  49. widget.onPress!(widget.menuList[i]);
  50. }
  51. },
  52. ),
  53. );
  54. }
  55. return menuTabList;
  56. }
  57. void chosenTab(item,int index){
  58. double containerWidth =menuTabListKey.currentContext!.size!.width;
  59. if(containerWidth/2<((index+1)*100-50)){
  60. _controller.animateTo((index+1)*100-containerWidth/2,duration: const Duration(seconds: 1), curve: Curves.ease);
  61. }else{
  62. _controller.animateTo(0,duration: const Duration(seconds: 1), curve: Curves.ease);
  63. }
  64. setState(() {
  65. currerValue =item['value'] as String;
  66. });
  67. }
  68. @override
  69. Widget build(BuildContext context) {
  70. return ListView(
  71. key: menuTabListKey,
  72. scrollDirection: Axis.horizontal,
  73. controller: _controller,
  74. children: generateMenuTabList(),
  75. );
  76. }
  77. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/463075
推荐阅读
相关标签
  

闽ICP备14008679号