美文网首页
Flutter实现马蜂窝小红书自适应高度轮播图

Flutter实现马蜂窝小红书自适应高度轮播图

作者: 阿明_1719 | 来源:发表于2019-08-16 18:29 被阅读0次

    最终效果

    项目地址

    演示代码地址

    image

    实现方法

    使用PageView组件

    NotificationListener可以监听PageView的改变,比如滑动的距离,页面索引等,目前只使用的了索引。里面的一些方法挺有用的。

                  NotificationListener(
                    onNotification: (ScrollNotification scrollInfo) {
                      // print(scrollInfo.metrics.pixels);
                      // print(scrollInfo.metrics.viewportDimension);
                      // print(_controller.page);
                      this.setState(() {
                        this.activeIndex = _controller.page.round();
                      });
                      return true;
                    },
                    child: PageView(
                        controller: _controller,
                        children: pictrueList
                            .map((PictrueData data) => FadeInImage.assetNetwork(
                                  placeholder: "lib/assets/loading_img.gif",
                                  image: data.url,
                                  fit: BoxFit.cover,
                                  alignment: Alignment.center,
                                ))
                            .toList()),
                  ),
    

    AnimatedContainer

    使用AnimatedContainer组件保证切换以后会有流程的过渡效果,表现的会平滑一些。

    完整代码

            AnimatedContainer(
              duration: Duration(milliseconds: 300),
              height: pictrueData.height * deviceWidth / pictrueData.width,
              curve: Curves.ease,
              child: Stack(
                children: <Widget>[
                  NotificationListener(
                    onNotification: (ScrollNotification scrollInfo) {
                      // print(scrollInfo.metrics.pixels);
                      // print(scrollInfo.metrics.viewportDimension);
                      // print(_controller.page);
                      this.setState(() {
                        this.activeIndex = _controller.page.round();
                      });
                      return true;
                    },
                    child: PageView(
                        controller: _controller,
                        children: pictrueList
                            .map((PictrueData data) => FadeInImage.assetNetwork(
                                  placeholder: "lib/assets/loading_img.gif",
                                  image: data.url,
                                  fit: BoxFit.cover,
                                  alignment: Alignment.center,
                                ))
                            .toList()),
                  ),
                  Positioned(
                    bottom: 10.0,
                    right: 10.0,
                    child: Container(
                      padding: EdgeInsets.symmetric(horizontal: 5.0, vertical: 3.0),
                      decoration: BoxDecoration(
                          color: Color.fromRGBO(0, 0, 0, 0.5),
                          borderRadius: BorderRadius.circular(20.0)),
                      child: Text(
                        '${activeIndex + 1}/${pictrueList.length}',
                        style: TextStyle(
                            color: const Color(0xffffffff), fontSize: 10.0),
                      ),
                    ),
                  )
                ],
              ),
            )
    

    重点

    首先,返回数据需要包含图片的宽高信息,就像这样:

      List<PictrueData> pictrueList = [
        PictrueData(
            width: 1920.0,
            height: 1152.0,
            url:
                "http://admin.soscoon.com/uploadImages/24294a8960f7cec4a5bb77276b8d1804eddc0023.jpg"),
        PictrueData(
            width: 550.0,
            height: 810.00,
            url:
                "http://admin.soscoon.com/uploadImages/72041ef01b9c8dd543511968d8659817c0086145.jpeg"),
        PictrueData(
            width: 1600.0,
            height: 900.00,
            url:
                "http://admin.soscoon.com/uploadImages/c236aa0af948e5d8812d23bd9eb1878682f247d8.jpg"),
        PictrueData(
            width: 1900.0,
            height: 1200.00,
            url:
                "http://admin.soscoon.com/uploadImages/41b2b4490204912f345b80be4fa88d7f5c9487a7.jpg"),
        PictrueData(
            width: 1920.0,
            height: 1000.00,
            url:
                "http://admin.soscoon.com/uploadImages/52a138c4dfcfbaab74daec69f128a2dd6dbf558f.jpg"),
      ];
    

    如果返回的只有图片信息没有宽高数据可以使用以下方法去获得图片的信息,这样也可以得到图片的宽高信息,不太建议,还是直接叫后端给,我们也方便处理,要是后端说他们给不了就拿上砖头去叫他们加,就想偷懒。

    class MyHomePage extends StatelessWidget {
      Widget build(BuildContext context) {
        Image image = new Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1564812422&di=a113f4b98d25442643ad9236f01ecbf5&src=http://hbimg.b0.upaiyun.com/0338cbe93580d5e6b0e89f25531541d455f66fda4a6a5-eVWQaf_fw658');
        Completer<ui.Image> completer = new Completer<ui.Image>();
        image.image.resolve(new ImageConfiguration()).addListener(
            ImageStreamListener(
                (ImageInfo info, bool _) => completer.complete(info.image)));
        return new Scaffold(
          appBar: new AppBar(
            title: new Text("Image Dimensions Example"),
          ),
          body: new ListView(
            children: [
              new FutureBuilder<ui.Image>(
                future: completer.future,
                builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
                  if (snapshot.hasData) {
                    return new Text(
                      '${snapshot.data.width}x${snapshot.data.height}',
                      style: Theme.of(context).textTheme.display3,
                    );
                  } else {
                    return new Text('Loading...');
                  }
                },
              ),
              image,
            ],
          ),
        );
      }
    }
    

    自适应轮播图的高度我们需要原始图片的宽高比,或者知道原始图的宽高。显示的时候按照原始的宽高比进行等比例缩放。

    _controller.page获取到的是一个浮点数,类似1.0325441,使用round四舍五入出现的效果就是我们拖到一半或以上就可以得到下一个activeIndexactiveIndex是一个整数。

    _controller.page

    flutter: 0.01314531968164951
    flutter: 0.026430343836238882
    flutter: 0.03609217958503115
    flutter: 0.048169474271021494
    flutter: 0.0517926626768186
    flutter: 0.0590390394884128
    flutter: 0.06386995736280894
    flutter: 0.9918596275657323
    flutter: 0.9928677347556618
    flutter: 0.9948281247819616
    flutter: 0.9955746971008173
    flutter: 0.9966901944924708
    flutter: 0.9971838269533462
    flutter: 0.9978950491069947
    flutter: 0.9981962948156735
    flutter: 0.998685063281176
    flutter: 1.0
    
    // 当前展示的banner图数据
    PictrueData pictrueData = pictrueList[activeIndex];
    // 等比缩放算出现在的高度
    height: pictrueData.height * deviceWidth / pictrueData.width,
    

    我们动态获取了图片的宽度以后放入AnimatedContainer就可以有过渡效果,真机和模拟器测试都很流畅,可以已60帧渲染。

    相关文章

      网友评论

          本文标题:Flutter实现马蜂窝小红书自适应高度轮播图

          本文链接:https://www.haomeiwen.com/subject/mvnqsctx.html