• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Flutter项目-第九篇 吸顶和滚动条嵌套

武飞扬头像
Javon_huang
帮助1

概要

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

一、滚动条嵌套

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

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

学新通

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

学新通

二、完整代码

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

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgakhkk
系列文章
更多 icon
同类精品
更多 icon
继续加载