Code前端首页关于Code前端联系我们

Flutter app开发实现无限轮播图

terry 2年前 (2023-09-23) 阅读数 74 #移动小程序

轮播图开发源于我的一个项目。正如您在文章末尾看到的,那是因为 pub 插件不能满足我的需求(或者不适合我的需求)。于是我决定自己写一个,先看看最终的效果。 Flutter app开发实现一个无限轮播图

图片来自网易云音乐。我一边听歌一边拿起它。侵权即除

阅读积分

其实实现起来非常简单。 Flutter 提供了 PageView 组件,该组件可以单独运行。要实现这样的滑动开关效果,实现无限轮播只存在一个小问题。有什么问题?别担心,我稍后再谈。

我们先从前端的角度思考如何创建一个无限轮播(为什么从前端的角度?因为我只是一个前端)。通常我的方法(你们所有人都展示自己的技能)是复制阵列照片顶部的最后一张照片。 ,将第一张图像复制到数组图像的末尾,然后在轮播到达最后一张图像后跳转到第二张图像,在轮播到达最后一张图像后跳转到倒数第二张图像第一张照片。打开。那么根据这个思路(惯性思维)我们首先实现这个无限轮播。

首先创建两个新文件carouselFlutter app开发实现一个无限轮播图

CustomPageView,CustomPageView是复制的 -code for Page查看:Flutter app开发实现一个无限轮播图

in 在轮播中创建一个新的StatefulWidget

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_samples/carousel/CustomPageView.dart';

class Carousel extends StatefulWidget {
  @override
  _State createState() => _State();
}

class _State extends State<Carousel> {
  PageController _pageController = PageController(initialPage: 1);//索引从0开始,因为有增补,所以这里设为1
  int _currentIndex = 1;
  List<String> _images = [
    'images/1.png',
    'images/2.png',
    'images/3.png',
    'images/4.png',
    'images/5.png',
    'images/6.png',
    'images/7.png',
    'images/8.png',
    'images/9.png',
  ];
  Timer _timer;//定时器
}
复制代码

第一个导入定时器有需要就用吧,没什么好说的。

接下来,设置一个计时器,因为我们要做的是自动轮播:

//设置定时器
_setTimer() {
    _timer = Timer.periodic(Duration(seconds: 4), (_) {
      _pageController.animateToPage(_currentIndex + 1,
          duration: Duration(milliseconds: 400), curve: Curves.easeOut);
    });
}
复制代码

通过periodic方法在此处设置一个计时器,每4秒运行一次。表演内容进入下一场。

然后处理图像数组:

  @override
  Widget build(BuildContext context) {
    List addedImages = [];
    if (_images.length > 0) {
      addedImages
        ..add(_images[_images.length - 1])
        ..addAll(_images)
        ..add(_images[0]);
    }
    return Scaffold(
      appBar: AppBar(
        elevation: 0.0,
        title: Text('Carousel'),
        centerTitle: true,
      ),
      body: AspectRatio(
        aspectRatio: 2.5,
        child:
      ),
    );
  }
复制代码

这里定义了一个addedImages,表示它是添加的图像数组(别忘了判断_images是否为空,虽然我们这里写的是Dead,但是思考是必要的)。

aspectRatio表示长宽比,AspectRatio根据传入的aspectRatio自动设置子组件的高度,高度根据组件的变化自动调整屏幕宽度。 (稍后我会向您展示效果),因此想要自定义它的人请记下笔记。

然后编写图像部分的代码:

 NotificationListener(
      onNotification: (ScrollNotification notification) {
        if (notification.depth == 0 &&
            notification is ScrollStartNotification) {
          if (notification.dragDetails != null) {
            _timer.cancel();
          }
        } else if (notification is ScrollEndNotification) {
          _timer.cancel();
          _setTimer();
        }
      },
      child: _images.length > 0
          ? CustomPageView(
              physics: BouncingScrollPhysics(),
              controller: _pageController,
              onPageChanged: (page) {
                int newIndex;
                if (page == addedImages.length - 1) {
                  newIndex = 1;
                  _pageController.jumpToPage(newIndex);
                } else if (page == 0) {
                  newIndex = addedImages.length - 2;
                  _pageController.jumpToPage(newIndex);
                } else {
                  newIndex = page;
                }
                setState(() {
                  _currentIndex = newIndex;
                });
              },
              children: addedImages
                  .map((item) => Container(
                        margin: EdgeInsets.all(10.0),
                        child: ClipRRect(
                          borderRadius: BorderRadius.circular(5.0),
                          child: Image.asset(
                            item,
                            fit: BoxFit.cover,
                          ),
                        ),
                      ))
                  .toList(),
            )
          : Container(),
    ),
复制代码

我们在onNotification中做了两件非常重要的事情。其中之一是当用户用手(或脚)滑动传送带时。当轮播滑动时取消计时器,当轮播滑动结束时重置计时器。

通知。深度表示此时事件的级别。这是什么意思?在Flutter中,事件也会冒泡,因此source(即最初发出事件的级别)为0。如果不明白,可以参考web事件并阅读文档。

notification.dragDetails 可以获取滑动位移。我们暂时不会在这里使用它。我们只确保用户移动了轮播。

每次轮播切换时,我们都会从CustomPageView返回到onPageChanged(即原来的PageView)调整以重置当前指数 .

以下是指标部分:

 Positioned(
      bottom: 15.0,
      left: 0,
      right: 0,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: _images
            .asMap()
            .map((i, v) => MapEntry(
                i,
                Container(
                  width: 6.0,
                  height: 6.0,
                  margin: EdgeInsets.only(left: 2.0, right: 2.0),
                  decoration: ShapeDecoration(
                      color: _currentIndex == i + 1
                          ? Colors.red
                          : Colors.white,
                      shape: CircleBorder()),
                )))
            .values
            .toList(),
      ),
    )
复制代码

重点来了。 dart中没有为List遍历方法提供索引(好像记不太清楚了),所以突出显示到当前项是一个小问题。有两种方法。一是创建一个新方法,通过方法中的for循环进行处理(我不太喜欢这样);二是文章中的方法。

首先将List通过as Card转换为Map,然后将MapFlutter app开发实现一个无限轮播图

中的 是index , value 就是值,然后可以通过 Mapmap 方法获取索引(如果你不知道,别忘了阅读文档)听不懂)。

然后只要调用定时器initState

 @override
  void initState() {
    print(_images.asMap());
    if (_images.length > 0) {
      _setTimer();
    }
    super.initState();
  }
复制代码

看看效果: Flutter app开发实现一个无限轮播图

眼尖的人可能已经注意到问题了,就是当他们看第一张或最后一张照片时滚动时会闪烁,即使用户滚动也会出现不理想的切换: Flutter app开发实现一个无限轮播图

这就是我上面说的,当时我用原来的PageView来制作无限轮播。问题是,当第一张和最后一张照片(实际上是所有照片)移动一半时,新页面就会更改。

其实无限轮播的效果已经达到了,只是有一个不和谐的小问题,所以只要解决了这个问题,无限轮播就完美了。

那么如何解决这个问题呢?我们看一下PageView的源码。有一段代码是这样的:

 onNotification: (ScrollNotification notification) {
    if (notification.depth == 0 && widget.onPageChanged != null && notification is ScrollUpdateNotification) {
      final PageMetrics metrics = notification.metrics;
      final int currentPage = metrics.page.round();
      if (currentPage != _lastReportedPage) {
        _lastReportedPage = currentPage;
        widget.onPageChanged(currentPage);
      }
    }
    return false;
  }
复制代码

小问题出现在这句话中:

notification is ScrollUpdateNotification
复制代码

这句话标识了类型通知,让它发生吧。 if中的代码在滚动过程中不断执行。一旦metrics.page的小数部分大于0.5,则得到metrics.page.round()。新的页面正在更改。

所以我们将这里的ScrollUpdateNotification更改为ScrollEndNotification。这就对了。它只有在到达滑动末端后才进行内部判断。就是这么简单。 Flutter app开发实现一个无限轮播图

当然也可以向PageControllerviewportFraction传递一个值,比如0.9,来实现视差效果:Flutter app开发实现一个无限轮播图

至此我们的无限轮播就实现了,最后。还有一点比较重要:别忘了销毁定时器:

@override
void dispose() {
    _timer?.cancel();
    super.dispose();
}
复制代码

自适应效果说:Flutter app开发实现一个无限轮播图

最后

文章中介绍的方法结合动画足以实现最常规的轮播效果了,自然。如果设计师能想出更清晰的效果图,你可能会想看看Scrollable,但这不是本文的重点。源代码在这里。

作者:MeFelixWang
链接:https://juejin.im/post/5d01f3436fb9a07ee85c2444
来源:掘金
版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明出处。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门