Flutter Sliver大家庭之Sliver实战④

暗恋的人总是经过一段暗恋后变得坚强,也已成长,成长到接受别人的爱,亦或去追求所爱,而这一切,好像与那个人无关。那个人何其无辜,被爱时他丝毫不知情,被爱后别人的坚强也好似和他无关,但不得不承认,他无意中造就了一个人的蜕变和成长,所以,那个人,又是何其伟大。

今日效果图:

效果图(1.1):

分析:

  • 使用NestedScrollView()完成 (滑动组件是用来处理复杂情况下的滑动应用场景,如向上滑动视图时,要折叠隐藏一部分内容,这时候就需要使用到 NestedScrollView 与 SliverAppBar 的结合使用。)
  • 使用RefreshIndicator()来刷新,完成上拉加载更多列表
  • 使用SliverAppBar来完成顶部头布局折叠效果
  • 使用PageView()来完成SliverAppBar中的滑动效果(这里也可以用Banner来实现)
  • 使用Timer使PageView自动滑动
  • 使用TabBar()和TabBarView()来实现底部的滑动效果

分析图(2.1):
在这里插入图片描述

整体布局搭建

使用NestedScrollView(),SliverAppBar(),TabBar()构建整体框架

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: initNestedScrollView(),
	);

	 NestedScrollView initNestedScrollView() {
	    return NestedScrollView(
	      headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
	        return [
	          ///初始化SliverAppBar
	          initSliverAppBar(),
	        ];
	      },
	      //初始化TabBar
	      body: _initTabBarView(),
	    );
	  }
}

SliverAppBar

初始化SliverAppBar:

 ///SliverAppBar
  Widget initSliverAppBar() {
      return SliverAppBar(
      expandedHeight: 280,
      //当snap = true时 这个参数必须为true!!!
      floating: false,

      //AppBar固定
      pinned: true,

      //AppBar跟随手指滑动而滑动  floating必须为true才可以使用
      snap: false,

      flexibleSpace: FlexibleSpaceBar(
        centerTitle: true,
        background: initPageView(),
      ),

      title: InkWell(
        onTap: () {
          Toast.toast(context, msg: "点击了搜索");
        },
        child: Container(
          height: 38,
          decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(color: Colors.white),
              borderRadius: BorderRadius.circular(20)),
          alignment: Alignment.center,
          child: Text(
            "搜索",
            style: TextStyle(color: Colors.black, fontSize: 18),
          ),
        ),
      ),
      bottom: PreferredSize(
        preferredSize: Size(MediaQuery.of(context).size.width, 44),
        child: TabBar(
          controller: _tabController,

          //Tab控制条颜色
          indicatorColor: Colors.blue,

          //字体颜色
          labelColor: Colors.black,

          //Tab粗细
          indicatorWeight: 3,

          //设置Tab字体与控制器一样大
          indicatorSize: TabBarIndicatorSize.label,

          //Tab是否平分
          isScrollable: false,

          tabs: [
            Tab(
              child: Text(
                "数学",
              ),
            ),
            Tab(
              child: Text(
                "英语",
              ),
            ),
          ],
        ),
      ),
    );
  }

SliverAppBar不了解的参考Flutter Slider大家族之SliverAppBar() 组件①

TabBarView

初始化:TabBarView():

class _CustomScrollWidget2State extends State<CustomScrollWidget2>
    with SingleTickerProviderStateMixin {
    
TabController _tabController;

  @override
  void initState() {
    super.initState();
    //Tab控制器
    initTabController();
    }
    
	void initTabController() {
	    _tabController = new TabController(
	      vsync: this,
	      length: 2,
	    );
	  }

	///TabBar
	  Widget _initTabBarView() {
	    return TabBarView(
	      controller: _tabController,
	      children: [
	        initListView("数学"),
	        initListView("英语"),
	      ],
	    );
	  }
	  
	 //初始化ListView
	  initListView(String s) {
	    return ListView.builder(
	      itemBuilder: (BuildContext context, int index) {
	        return Container(
	          height: 50,
	          alignment: Alignment.center,
	          child: Text("$s$index"),
	        );
	      },
	      itemCount: 30,
	    );
	  }
}

这段代码很简单,通过初始化TabBarView在TabBarView’页面’添加ListView

这里需要注意的是:

  • TabController中length参数
  • TabBarView中参数children[]
  • Tab()参数

他们三者参数一定要对应起来!!

比如我现在TabController中length参数为2,那么我的TabBarView参数children[]就必须有2个子条目,Tab()参数也必须有2个

来看看现在的效果:

效果图(1.2):

PageView

PageView参数类型说明
scrollDirectionAxis设置滚动方向Axis.vertical垂直滚动
Axis.horizontal
controllerPageController控制器
onPageChangedValueChanged<int>响应当前页数
childrenList<Widget>子Page的Widget
PageController参数类型说明
viewportFractiondouble设置每一个Page不占满屏幕,漏出上一个和下一个Page!
initialPageint设置默认显示page
keepPagebool是否保存当前page状态

 //初始化PageView
  Widget initPageView() {
    return Stack(
      children: [
        //PageView
        buildPageView(),
      ],
    );
  }
  
//创建PageView
  Widget buildPageView() {
    return Container(
      color: Colors.white,
      padding: EdgeInsets.all(10),
      child: PageView(
        controller: _pageController,
        children: [
          initPageItem(Colors.deepPurple, "Page1"),
          initPageItem(Colors.deepOrange, "Page2"),
          initPageItem(Colors.yellow, "Page3"),
          initPageItem(Colors.lightGreenAccent, "Page4"),
        ],
        onPageChanged: (index) {
          setState(() {
            _index = index;
          });
        },
      ),
    );
  }

Widget initPageItem(Color color, String title) {
    return Container(
      decoration:
          BoxDecoration(color: color, borderRadius: BorderRadius.circular(20)),
      alignment: Alignment.center,
      child: Text(title),
    );
  }

PageController(PageView控制器):


  PageController _pageController;
 
 //默认从0开始
   int _index = 0;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _pageController = PageController(
        viewportFraction: 0.9, //设置每一个Page不占满屏幕,漏出上一个和下一个Page!
        initialPage: _index, //设置默认Page
        keepPage: true //是否保存当前滚动page
        );
  }

效果图(1.3):

给PageView添加圆点指示

使用层叠布局,在PageView下面创建圆点

 //初始化PageView
  Widget initPageView() {
    return Stack(
      children: [
        //PageView
        buildPageView(),

        //滑动圆点
         buildRound(),
      ],
    );
  }
  //默认从0的位置开始
  int _index = 0;
 //滑动圆点
  Positioned buildRound() {
    return Positioned(
      left: 20,
      right: 20,
      bottom: 60,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          initRound(_index == 0),
          initRound(_index == 1),
          initRound(_index == 2),
          initRound(_index == 3),
        ],
      ),
    );
  }

使用AnimatedContainer()动画初始化圆:

//初始化圆
  Widget initRound(bool isselect) {
    return AnimatedContainer(
      duration: Duration(milliseconds: 800),
      width: isselect ? 30 : 10,
      height: 10,
      margin: EdgeInsets.only(left: 5, right: 5),
      curve: Curves.fastOutSlowIn,
      decoration: BoxDecoration(
        color: isselect ? Colors.black : Colors.white,
        borderRadius: BorderRadius.circular(20),
      ),
    );
  }

AnimatedContainer不熟悉的请参考Flutter Animated动画(2.7)

来看看现在的效果:

效果图(1.4):

Timer

使用Timer使PageView()每过3s自动滑动

 Timer _timer;
int _index = 0;
 
  @override
  void initState() {
    super.initState();
	_timer = new Timer.periodic(new Duration(seconds: 3), (timer) {
	      if (mounted) {
		        setState(() {
		          _index++;
		          if (_index == 4) {
		            _index = 0;
		          }
		          //设置PageView滑动到的页面
		          _pageController.animateToPage(_index,
		              duration: Duration(seconds: 2), curve: Curves.ease);
		        });
	      }
    });
}
  • 使用:_pageController.animateToPage(_index,
    duration: Duration(seconds: 2), curve: Curves.ease);
    来设置PageView对应位置

效果图(1.5):

RefreshIndicator

使用RefreshIndicator完成加载更多

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: RefreshIndicator(
      
        //下拉刷新回调方法
        onRefresh: initRefresh;
        
        //可滚动组件在滚动时会发送ScrollNotification类型的通知
        notificationPredicate: (ScrollNotification notifation) {
          //该属性包含当前ViewPort及滚动位置等信息
          ScrollMetrics scrollMetrics = notifation.metrics;
          if (scrollMetrics.minScrollExtent == 0) {
            return true;
          } else {
            return false;
          }
        },
        //NestedScrollView(
        child: initNestedScrollView(),
      ),
    );
  }
  
	initRefresh() async {
	    //模拟网络刷新 等待2秒
	    await Future.delayed(Duration(milliseconds: 2000)).then((value) {
	      Toast.toast(context, msg: "已刷新");
	    });
	    //返回值以结束刷新
	    return Future.value(true);
  }

一般会使用 NestScrollView 结合 SliverAppBar, TabBarView 还有下拉刷新组件 RefreshIndicator 来组合实可折叠头部的UI布局文件。 但是在使用官方的下拉刷新 RefreshIndicator发现没法使用,如果使用了折叠效果会消失。

原因是:
默认的RefreshIndicator要求它的子child必须是第一层的滑动组件它才其效果
在这里插入图片描述
在来看看最终效果:
效果图(1.6):

完整代码

完整项目

猜你喜欢:

Flutter Sliver大家族之CustomScrollView和SliverAppBar 组件①

Flutter Sliver大家族之SliverList(),SliverFixedExtentList(),SliverGrid()组件②

Flutter Sliver大家族之SliverPersistentHeader()和SliverToBoxAdapter()组件③

原创不易,您的点赞就是对我最大的支持,点个赞支持一下吧~

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

s10g

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值