博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Flutter教程-自定义无限滚动轮播器infinity_slider
阅读量:7052 次
发布时间:2019-06-28

本文共 7919 字,大约阅读时间需要 26 分钟。

简介

通过组合PageView方式,实现一个自定义的infinity_slider小部件,完整代码

  1. 支持无限滚动
  2. 支持定时器滚动
  3. 支持曲线滚动

步骤

1)创建一个有状态的小部件

新建infinity_slider.dart文件,添加下方代码

import 'package:flutter/material.dart';class InfinitySlider extends StatefulWidget {  @override  _InfinitySliderState createState() => _InfinitySliderState();}class _InfinitySliderState extends State
{ @override Widget build(BuildContext context) { return Container(); }}复制代码

2)添加可配置参数

  1. 要知道PageView小部件是没有设置可无限滚动属性的
  2. 我们有一个需要滑动且长度为5的小部件列表items
  3. PageView.builder有个itemCount字段,当我们构建PageView时,如果没有设置itemCount的话则PageViewitemBuilder会从0-(PageController.initialPage)-infinity 构建滑块,这时items会有溢出的危险。
  4. 你想到了什么?假如我们有一个小部件列表items,我们可以通过一个函数计算出当前的items真实下标,这时items就可以向右进行无限滑动而不用担心items下标的溢出,计算函数代码如下
int _calcIndex(int input, int source) {  final int result = input % source;  return result < 0 ? source + result : result;}/** * _getRealIndex * * @param {int} position - 真实下标 * @param {int} base - 初始真实下标 * @return {int} length 滑块列表长度 * * @since 1.0.0 */int _getRealIndex(int position, int base, int length) {  final int offset = position - base;  return _calcIndex(offset, length);}复制代码
  1. 有了这个计算函数,让我们来写一写相关代码
import 'package:flutter/material.dart';import 'dart:async';int kRealPage = 100;int _calcIndex(int input, int source) {  final int result = input % source;  return result < 0 ? source + result : result;}int _getRealIndex(int position, int base, int length) {  final int offset = position - base;  return _calcIndex(offset, length);}typedef void UpdatePageCallback(int index);class InfinitySlider extends StatefulWidget {  final int initialPage;  final List
items; final double height; final PageController pageController; InfinitySlider({ Key key, @required this.items, this.height: 120, this.initialPage: 0, }) : pageController = new PageController( initialPage: kRealPage + initialPage, ), assert(items != null), assert(items.length > 0), assert(initialPage != null), super(key: key); @override _InfinitySliderState createState() => _InfinitySliderState();}class _InfinitySliderState extends State
{ @override Widget build(BuildContext context) { return Container( height: widget.height, child: PageView.builder( itemBuilder: (BuildContext context, int i) { final int index = _getRealIndex(i, kRealPage, widget.items.length); return widget.items[index]; }, controller: widget.pageController, ), ); }}复制代码

3)解决向左无限滚动

  1. 在上面代码中,kRealPage被我们设置为100,假如遇到一个无聊的人往左滑动了100次,这时就不能再次往左侧滑动
  2. 我们可以将kRealPage设置为100000000,虽然不会有那么无聊的人往左滑动一亿次,但是我们要解决这个问题
  3. 让我们监听PageController滑动事件
import 'package:flutter/material.dart';import 'dart:async';int kRealPage = 100;int _calcIndex(int input, int source) {  final int result = input % source;  return result < 0 ? source + result : result;}int _getRealIndex(int position, int base, int length) {  final int offset = position - base;  return _calcIndex(offset, length);}typedef void UpdatePageCallback(int index);class InfinitySlider extends StatefulWidget {  final int initialPage;  final List
items; final double height; final PageController pageController; InfinitySlider({ Key key, @required this.items, this.height: 120, this.initialPage: 0, }) : pageController = new PageController( initialPage: kRealPage + initialPage, ), assert(items != null), assert(items.length > 0), assert(initialPage != null), super(key: key); @override _InfinitySliderState createState() => _InfinitySliderState();}class _InfinitySliderState extends State
{ @override void initState() { super.initState(); widget.pageController.addListener(() { if (widget.pageController.page == (kRealPage - widget.items.length) || widget.pageController.page == (kRealPage + widget.items.length)) { widget.pageController.position .setPixels(MediaQuery.of(context).size.width * kRealPage); } }); } @override Widget build(BuildContext context) { return Container( height: widget.height, child: PageView.builder( itemBuilder: (BuildContext context, int i) { final int index = _getRealIndex(i, kRealPage, widget.items.length); return widget.items[index]; }, controller: widget.pageController, ), ); }}复制代码

4)添加剩余的功能

  1. 完整的代码如下
import 'package:flutter/material.dart';import 'dart:async';int kRealPage;double kAutoMaxPage;double kAutoMinPage;int _calcIndex(int input, int source) {  final int result = input % source;  return result < 0 ? source + result : result;}int _getRealIndex(int position, int base, int length) {  final int offset = position - base;  return _calcIndex(offset, length);}typedef void UpdatePageCallback(int index);class InfinitySlider extends StatefulWidget {  final int initialPage;  final List
items; final bool autoPlay; final Duration interval; final Curve transCurve; final Duration transDuration; final double height; final PageController pageController; final UpdatePageCallback updateCallback; InfinitySlider({ Key key, @required this.items, this.height: 120, this.initialPage: 0, this.autoPlay: true, this.interval: const Duration(seconds: 2), this.transDuration: const Duration(milliseconds: 800), this.transCurve: Curves.fastOutSlowIn, this.updateCallback, }) : pageController = new PageController( initialPage: kRealPage + initialPage, ), assert(items != null), assert(items.length > 0), assert(initialPage != null), assert(autoPlay != null), assert(interval != null), assert(transDuration != null), assert(transCurve != null), super(key: key) { kRealPage = items.length; kAutoMinPage = 0.0; kAutoMaxPage = (items.length * 2).toDouble(); } @override _InfinitySliderState createState() => _InfinitySliderState(); Future
nextPage({Duration duration, Curve curve}) { return pageController.nextPage(duration: duration, curve: curve); } Future
previousPage({Duration duration, Curve curve}) { return pageController.previousPage(duration: duration, curve: curve); }}class _InfinitySliderState extends State
{ int currentPage; Timer timer; @override void initState() { super.initState(); widget.pageController.addListener(() { if (widget.pageController.page == kAutoMinPage || widget.pageController.page == kAutoMaxPage) { widget.pageController.position .setPixels(MediaQuery.of(context).size.width * kRealPage); } }); currentPage = widget.initialPage; if (widget.autoPlay) { timer = new Timer.periodic(widget.interval, (_) { widget.nextPage( duration: widget.transDuration, curve: widget.transCurve); }); } } @override Widget build(BuildContext context) { return Container( height: widget.height, child: PageView.builder( itemBuilder: (BuildContext context, int i) { final int index = _getRealIndex(i, kRealPage, widget.items.length); return widget.items[index]; }, controller: widget.pageController, onPageChanged: (int index) { currentPage = _getRealIndex(index, kRealPage, widget.items.length); if (widget.updateCallback != null) widget.updateCallback(currentPage); }, ), ); } @override void dispose() { super.dispose(); timer?.cancel(); }}复制代码

5)使用这个小部件

InfinitySlider(    items: [1,2,3,4,5].map((i) {      return Builder(        builder: (BuildContext context) {          return Container(            width: MediaQuery.of(context).size.width,            color: Colors.amber            child: new Text('text $i', style: new TextStyle(fontSize: 16.0),)          );        },      );    }).toList(),)复制代码

转载于:https://juejin.im/post/5c638fe06fb9a04a0164d1a1

你可能感兴趣的文章
Android SDK Manager连不上Google服务器的解决办法
查看>>
js常用的事件
查看>>
正则表达式
查看>>
Mysql zip的下载地址
查看>>
动态代理模式
查看>>
将博客搬至CSDN
查看>>
JQuery 修改 form 表单的 action 的值,并提交
查看>>
IOS 百度地图导入最新 SDK 2.9 报错
查看>>
android 显示 网络图片
查看>>
安装MySQLdb模块-python
查看>>
ubuntu快捷键
查看>>
IOS——生成智能调试输出
查看>>
杀毒软件Avast被曝严重的0day漏洞
查看>>
NDK Caused by: java.lang.UnsatisfiedLinkError:
查看>>
oracle timestamp相减
查看>>
【swing】 BoxLayout布局
查看>>
Android 属性动画(Property Animation)完全解析 (下)
查看>>
GC overhead limit exceeded
查看>>
JDBC学习之三
查看>>
CSS3 渐变(Gradients)
查看>>