Flutter制作图片横幅轮播
制作店面应用时,需要用到轮播。我看到flutter的控件库中没有这样的控件(当然,也许我只是错过了),所以我决定自己做一个banner轮播。该照片已发布。
框架
- 整体框架是PageView,一个指示器和一个计时器。
- PageView 用于显示需要播放的小部件。它不必仅限于显示图像。
- 指示器用作当前图像的指示器,需要指示Page关注当前。并且指示器应该能够设置半径、选定的颜色和未选定的颜色。最后,你可以设置标志的位置,左上,右下。
- 定时器,当节目需要定时播放时,就会按照设定的时间间隔播放对应的widget。这里需要注意的是,当你按下手的时候,需要取消时间限制,当你松开点击的时候,需要重新设置时间限制。当接口被销毁时,定时器也被销毁。
- Page点击了一下,又显示来电了。点击播放Page时需要以适当的方式回调。
应用
1. PageView
的实现如上代码:
_controller = PageController(
initialPage: ,
);
Widget pageView = GestureDetector(
onHorizontalDragDown: _onTaped,
onTap: _onPageClicked,
child: PageView(
children: widget.childWidget,
scrollDirection: widget.scrollDirection,
onPageChanged: onPageChanged,
controller: _controller,
),
);
Page Controller是一个Page控制器。可以设置Page的首次显示,也可以设置多张图片滚动时释放页面。您可以通过滚动来设置部分显示区域。可以外部调用initialPage,默认设置为0。
2。实现指针
上面的代码:
Widget indicatorWidget = Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: widget.childWidget.map(
(f) {
int index = (f);
Widget indicatorWidget = Container(
width: ().width,
height: ().height,
margin: (right: ),
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: index == selectedPage
? widget.indicatorSelectedColor
: widget.indicatorColor,
),
);
return indicatorWidget;
},
).toList(),
);
当多个widget需要旋转时,默认指针按数字排序并显示在中间。唯一的子索引是一个圆,颜色和半径可以外部设置。所选Page的标志应为所选颜色,其他指标应为非所选颜色。 ? ,否则需要使用 Stack 来堆叠这两个 widget。PageView在底部,标志在顶部。如今,它的位置也可以从外部设置。指针的位置可以通过Align来确定,通常是在bottom之上,所以这里给Positioned的bottom参数设置一个值。当然,我们也可以为这个位置以及距该位置的距离提供一个外部接口。
这里最后要做的是设置这个stackWidget的文本方向,因为在某些国家文本阅读方向是从右到左。如果您现在不安装,将会显示错误。我这里是从左到右写的。 :
Widget parent = Directionality(
textDirection: TextDirection.ltr,
child: Container(
width: widget.width, height: widget.height, child: stackWidget));
当然,Android提供了试用方法:
Configuration config = getResources().getConfiguration();
if(() == ) {
//in Right To Left layout
}
现在widget级别就结束了。
4。计时器
连续启动。该方法是flutter提供的:
void _startTimer() {
if ( <= 0) {
return;
}
var oneSec = Duration(seconds: );
_timer = new Timer.periodic(oneSec, (Timer timer) {
++selectedPage;
selectedPage = selectedPage % widget.childWidget.length;
_controller?.jumpToPage(selectedPage);
onPageChanged(selectedPage);
});
}
autoDisplayInterval 外部设置时间间隔。如果不设置,默认情况下不会自动播放。如果设置为大于0的数字,则会自动播放。时间间隔为秒。另外,每次激活时,选择播放的页数都会增加1,剩下的页数就是当前应该播放的页数。同时需要设置跳转到指定页面并再次调用播放页面序号。给来电者。
这里,当我们按下书页时,如果不加以处理,就会出现一团乱七八糟的漩涡。在这里我们必须处理它。我记得PageView定义的时候,最外层包裹着一个GestureDetector。我们需要处理Page被点击拖动水平移动的场景,所以我们有一个场景来处理HorizontalDragDown和onTap这两个回调函数。
onTap用于tap处理,直接携带序列号token来呼叫调用者。
onHorizontalDragDown 用于水平向下拖动。特殊处理为:
void _onHorizontalDragDown(DragDownDetails details) {
if (_timer == null) {
return;
}
_releaseTimer();
(Duration(seconds: 2));
_startTimer();
}
每按一次按钮,定时器停止,释放定时器,定时器延迟2秒。如果这段时间有新闻,把它拖进去,再删除。
如果有2秒的延迟并且没有其他处理,则继续预定的播放过程。参见预定的销毁方法:
void _releaseTimer() {
if (_timer != null && !) {
return;
}
_timer?.cancel();
_timer = null;
}
给定外部环境
下一步是将指定进程的调用者需要的参数暴露给外部环境,并在构造时传递:
BannerWidget(
{Key key,
@required this.childWidget,//子视图列表
this.enableIndicator = true,//是否允许显示指示器
this.initPage = 0,//初始页面序号
this.height = 36,//高度
this.width = 340,//宽度
this.indicatorRadius = 4,//指示器半径
this.indicatorColor = Colors.white,//指示器默认颜色
this.indicatorSelectedColor = Colors.red,//页面被选中指示器颜色
this.scrollDirection = Axis.horizontal,//滚动方向(默认水平)
this.indicatorSpaceBetween = 6,//指示器之间的间距
this.autoDisplayInterval = 0,//自动播放时间间隔(不设置或设置为0,则不自动播放)
页面被展示回调
this.indicatorAlign = Alignment.bottomCenter,//指示器位置
})//页面被点击回调
: super(key: key);
子视图列表必须提供要播放的内容。从上到下:是否显示索引、首页页码、高度、宽度、宽高比、索引颜色、所选索引颜色、滚动方向(默认水平)、指示器之间的间隔、自动播放时间(如果不显示) 。设置或设置为0,不会自动播放)、页面显示时回调、占位符、页面点击时回调。
使用方法
var images = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
};
void main() => runApp(BannerWidget(
width: 340,
height: 56,
autoDisplayInterval: 2,
childWidget: ((f) {
return Image.network(
f,
width: 340,
height: 48,
);
}).toList(),
));
最后一英里
import 'dart:async';
import 'package:flutter/';
class BannerWidget extends StatefulWidget {
BannerWidget(
{Key key,
@required this.childWidget,
this.enableIndicator = true,
this.initPage = 0,
this.height = 36,
this.width = 340,
this.indicatorRadius = 4,
this.indicatorColor = Colors.white,
this.indicatorSelectedColor = Colors.red,
this.scrollDirection = Axis.horizontal,
this.indicatorSpaceBetween = 6,
this.autoDisplayInterval = 0,
this.onPageSelected,
this.indicatorAlign = Alignment.bottomCenter,
})
: super(key: key);
final double width;
final double height;
final List childWidget;
final Axis scrollDirection;
final ValueChanged onPageSelected;
final ValueChanged onPageClicked;
final int initPage;
final bool enableIndicator;
final Color indicatorSelectedColor;
final Color indicatorColor;
final double indicatorRadius;
final double indicatorSpaceBetween;
final int autoDisplayInterval;
final Alignment indicatorAlign;
@override
__BannerWidgetState createState() => __BannerWidgetState();
}
class __BannerWidgetState extends State {
int selectedPage = 0;
PageController _controller;
Timer _timer;
int lastTapDownTime = 0;
void onPageChanged(int index) {
setState(() {
selectedPage = index;
});
widget?.onPageSelected(index);
}
void _startTimer() {
if ( <= 0) {
return;
}
var oneSec = Duration(seconds: );
_timer = new Timer.periodic(oneSec, (Timer timer) {
++selectedPage;
selectedPage = selectedPage % widget.childWidget.length;
_controller?.jumpToPage(selectedPage);
onPageChanged(selectedPage);
});
}
void _releaseTimer() {
if (_timer != null && !) {
return;
}
_timer?.cancel();
_timer = null;
}
void _onHorizontalDragDown(DragDownDetails details) {
if (_timer == null) {
return;
}
_releaseTimer();
(Duration(seconds: 2));
_startTimer();
}
void _onPageClicked() {
widget?.onPageClicked(selectedPage);
}
@override
void initState() {
();
_startTimer();
}
@override
Widget build(BuildContext context) {
_controller = PageController(
initialPage: ,
);
Widget pageView = GestureDetector(
onHorizontalDragDown: _onHorizontalDragDown,
onTap: _onPageClicked,
child: PageView(
children: widget.childWidget,
scrollDirection: widget.scrollDirection,
onPageChanged: onPageChanged,
controller: _controller,
),
);
Widget indicatorWidget = Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: widget.childWidget.map(
(f) {
int index = (f);
Widget indicatorWidget = Container(
width: ().width,
height: ().height,
margin: (right: ),
decoration: new BoxDecoration(
shape: BoxShape.circle,
color: index == selectedPage
? widget.indicatorSelectedColor
: widget.indicatorColor,
),
);
return indicatorWidget;
},
).toList(),
);
Widget stackWidget = widget.enableIndicator
? Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
pageView,
Positioned(
bottom: 6,
child: Align(
alignment: widget.indicatorAlign,
child: indicatorWidget,
),
),
],
)
: pageView;
Widget parent = Directionality(
textDirection: TextDirection.ltr,
child: Container(
width: widget.width, height: widget.height, child: stackWidget));
return parent;
}
@override
void dispose() {
();
_releaseTimer();
}
}
var images = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
};
void main() => runApp(BannerWidget(
width: 340,
height: 56,
autoDisplayInterval: 2,
childWidget: ((f) {
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。