FLUTTER 无限滚动栏 banner方案

BANNER 是应用中最常见的复合控件之一,当然也有无数种功能齐全好看好使的第三方工具。这里写一个最简单的三页式BANNER,了解一下PageController,Timer的用法以及一些简单的方法封装

基本思路

  1. 使用PageController设置一个三页翻页控件
  2. 显示中页 并给三页按照顺序放置BANNER控件
  3. 在滚动到前/后页的时刻回到中页并同时更换三页的控件内容
  4. 添加自动滚动的定时器

实现

  1. 首先创建创建一个StatefulWidget 并令其驻留在内存中以保存滚动状态

    flutter
    class _BannerItemState extends State<BannerItem> with AutomaticKeepAliveClientMixin{
     @override
     bool get wantKeepAlive => true;
    
  2. 初始化一个数据源,这里我是用array存一组IMAGE作为数据源,控件的内容从数组中获取,只需更新数组就可以了。 默认状态可以放一个占位图,这里我就放放一个空白控件当占位
    //数据源
    List imageList = [new Container()];

  3. 布局 界面上使用一个有三个 child的pageview即可,中间的控件在底部放上按钮以传出点击事件

//中间页下标
  int _cur = 0;
  
  PageController _pageController = new PageController(initialPage: 1,
  keepPage: true,viewportFraction: 1.0);
  @override
Widget build(BuildContext context) {
 // TODO: implement build
 super.build(context);
 return new Container(
   height: 150,
   color:SkinConfig.instance.randomColor(),
   child:getPageView(),
   alignment: Alignment.center,

 );
   

}

Widget getPageView(){
 return PageView(

   children: <Widget> [
   
     new Container(color: SkinConfig.instance.mainBGColor(),
     alignment: Alignment.center,
     child: imageList[preNum()] ,
     padding: EdgeInsets.all(0),),
     
     new Container(color: SkinConfig.instance.mainBGColor(),
     alignment: Alignment.center,
       child: new FlatButton(onPressed: btnTouched,
       child: imageList[_cur],padding: EdgeInsets.all(0),),
       padding: EdgeInsets.all(0),  ),
     
     new Container(color: SkinConfig.instance.mainBGColor(),
     alignment: Alignment.center,
     child: imageList[nextNum()] ,
     padding: EdgeInsets.all(0),),
   ],
   scrollDirection: Axis.horizontal,
//      onPageChanged: pageChanged,
   controller: _pageController,
 );
}
//前页
int preNum(){

 return _cur - 1>=0?_cur-1:imageList.length - 1;

}
//后页
int nextNum(){

 return _cur + 1 <imageList.length ?_cur + 1:0;

}

布局,前中后页获取就完成了

  1. 在滚动结束的事件回到中页并完成_cur的切换
 void changePage(int pageCount){
    //向后滚动
    setState(() {
      if(pageCount == 2){

        _cur++;

        if(_cur == imageList.length){
          _cur = 0;
        }
      }
      //向前滚动
      if(pageCount == 0){
        _cur--;
        if(_cur == -1){
          _cur = imageList.length - 1;
        }
      }
    });
  }
  1. 监听滚动事件,在滚动到前/后页的时候回到中页并切换数据
    _pageController.addListener((){

      if( _pageController.offset <= 0 ){

        _pageController.jumpToPage(1);

        changePage(0);

      }
      if( _pageController.offset >= 2 * MediaQuery.of(context).size.width ){

        _pageController.jumpToPage(1);

        changePage(2);
      }
    });

  1. 添加自动滚动的定时器,记得在销毁的时候撤掉定时器
    _timer = Timer.periodic(const Duration(seconds: 5), (Timer timer){

      _pageController.animateToPage(2, duration: const Duration(seconds: 2), curve: Curves.fastOutSlowIn);

    });
//
  @override
  void dispose() {
  
    _timer.cancel();
    // TODO: implement dispose
    super.dispose();
  }
  1. 最后从你的数据源获取数据并替换数据源数组即可
Future<Null>requestData()async{

   print('banner request');
   HttpClient httpClient = new HttpClient();

   Uri uri=Uri(scheme: "http", host: URLbaseWWW,path:PATHBanner , queryParameters: {
   'id' : 'NEWS_POP'
   });
   HttpClientRequest request = await httpClient.getUrl(uri);

   HttpClientResponse response = await request.close();

   String responseBody = await response.transform(utf8.decoder).join();

   Map result = json.decode(responseBody);

   List dataList = result['Data'];
//取得数据
   setState(() {
     for(var i = 0 ;i < dataList.length;i++){

       Map dict = dataList[i];
       String path = 'http://' + URLbaseWWW + dict['BannerImage'];
  //将数据添加到数据源中
       imageList.add(new Image.network(path,height: MediaQuery.of(context).size.width / 16 * 9 ,width:MediaQuery.of(context).size.width,fit: BoxFit.fill,));
     }
     //移除数据源中不需要的元素
    while(imageList.length > dataList.length){

       imageList.removeAt(0);
     }
   });
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值