Flutter app开发实现无限轮播图
轮播图开发源于我的一个项目。正如您在文章末尾看到的,那是因为 pub 插件不能满足我的需求(或者不适合我的需求)。于是我决定自己写一个,先看看最终的效果。
图片来自网易云音乐。我一边听歌一边拿起它。侵权即除
阅读积分
其实实现起来非常简单。 Flutter 提供了 PageView
组件,该组件可以单独运行。要实现这样的滑动开关效果,实现无限轮播只存在一个小问题。有什么问题?别担心,我稍后再谈。
我们先从前端的角度思考如何创建一个无限轮播(为什么从前端的角度?因为我只是一个前端)。通常我的方法(你们所有人都展示自己的技能)是复制阵列照片顶部的最后一张照片。 ,将第一张图像复制到数组图像的末尾,然后在轮播到达最后一张图像后跳转到第二张图像,在轮播到达最后一张图像后跳转到倒数第二张图像第一张照片。打开。那么根据这个思路(惯性思维)我们首先实现这个无限轮播。
首先创建两个新文件carousel
和
CustomPageView,CustomPageView
是复制的 -code for Page查看:
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
循环进行处理(我不太喜欢这样);二是文章中的方法。
首先将 中的 然后只要调用定时器 看看效果: 眼尖的人可能已经注意到问题了,就是当他们看第一张或最后一张照片时滚动时会闪烁,即使用户滚动也会出现不理想的切换: 这就是我上面说的,当时我用原来的 其实无限轮播的效果已经达到了,只是有一个不和谐的小问题,所以只要解决了这个问题,无限轮播就完美了。 那么如何解决这个问题呢?我们看一下 小问题出现在这句话中: 这句话标识了类型 所以我们将这里的 当然也可以向 至此我们的无限轮播就实现了,最后。还有一点比较重要:别忘了销毁定时器: 自适应效果说: 文章中介绍的方法结合动画足以实现最常规的轮播效果了,自然。如果设计师能想出更清晰的效果图,你可能会想看看 作者:MeFelixWangList
通过as Card
转换为Map
,然后将Map
键
是index , value
就是值,然后可以通过 Map
的 map
方法获取索引(如果你不知道,别忘了阅读文档)听不懂)。 initState
: @override
void initState() {
print(_images.asMap());
if (_images.length > 0) {
_setTimer();
}
super.initState();
}
复制代码
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
。这就对了。它只有在到达滑动末端后才进行内部判断。就是这么简单。 PageController
的viewportFraction
传递一个值,比如0.9,来实现视差效果:@override
void dispose() {
_timer?.cancel();
super.dispose();
}
复制代码
最后
Scrollable
,但这不是本文的重点。源代码在这里。
链接:https://juejin.im/post/5d01f3436fb9a07ee85c2444
来源:掘金
版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明出处。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。