本文适合Flutter初学者,没有过多的深入内容,一起来感受flutter的魅力吧。
在原生安卓中,viewPager还是有一定难度的,通常我们要配合fragment及adapter使用,还要去管理fragment的生命周期。代码量还是有的。
如何在flutter里实现ViewPager呢?
答案很简单,flutter为我们封装了一个PageView的Widget,只要善用它,就可以搞定了。
先来看最简单的情况,我们的Page均为Image的情况,而且我们不需要监听事件,仅仅是用户可以滑动,展示。
先把Flutter的模版写好。
import 'package:flutter/material.dart';
void main() {
runApp(ViewPager());
}
class ViewPager extends StatelessWidget {
}
class ViewPagerStateful extends StatefulWidget {
}
class ViewPagerState extends State<ViewPagerStateful> {
}
顺序如下,main函数创建ViewPager,ViewPager中代码创建ViewPagerStateFul,ViewPagerStateFul中创建ViewPagerState,通过ViewPagerState改变状态。在这里,我们不需要改变ViewPager的状态,所以ViewPagerStateful应该继承于StatelessWidget。
改继承自然要改名,于是,我们的模版如下:
import 'package:flutter/material.dart';
void main() {
runApp(ViewPager());
}
class ViewPager extends StatelessWidget {
}
class ViewPagerStateless extends StatelessWidget {
}
根据上述的顺序,我们开始往其中填写代码。
先填ViewPager,它就是我们的整个可见页面。
class ViewPager extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "ViewPager",
theme: ThemeData(primaryColor: Colors.blue),
home: ViewPagerStateless(),
);
}
}
设置一个主题,并包裹我们的ViewPagerStateless。
接下来就是重中之重了,使用PageView来创建我们的ViewPager。
class ViewPagerStateless extends StatelessWidget {
// 小米官网找的图。嗯,来源,小米新出的cc。
var imgs = [
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-02.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-03.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-04.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-05.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-06.png"
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ViewPager")),
body: PageView(
children: <Widget>[
Image.network(imgs[0]),
Image.network(imgs[1]),
Image.network(imgs[2]),
Image.network(imgs[3]),
Image.network(imgs[4]),
],
),
);
}
}
appBar用来设置标题栏。
Image.network的命名构造方法可以直接帮我们把网络的图片下载并显示出来。
PageView也很容易,设置一下children的list,就可以显示了。
目前的完整代码如下:
import 'package:flutter/material.dart';
void main() {
runApp(ViewPager());
}
class ViewPager extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "ViewPager",
theme: ThemeData(primaryColor: Colors.blue),
home: ViewPagerStateless(),
);
}
}
class ViewPagerStateless extends StatelessWidget {
var imgs = [
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-02.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-03.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-04.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-05.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-06.png"
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ViewPager")),
body: PageView(
children: <Widget>[
Image.network(imgs[0]),
Image.network(imgs[1]),
Image.network(imgs[2]),
Image.network(imgs[3]),
Image.network(imgs[4]),
],
),
);
}
}
run起来效果如下:
这时候,我们已经可以左右的滑动了,也会有回弹的效果。
当然了,我们肯定不能满足这样的一个静态效果,所以,我们把ViewPagerStateless删除掉,建立ViewPagerStateful。
在Flutter中,StatefulWidget是有状态的小部件,StatelessWidget是无状态的小部件,有状态的小部件才能更新哦。
class ViewPagerStateful extends StatefulWidget {
@override
ViewPagerState createState() {
return ViewPagerState();
}
}
这是有状态小部件标准写法了。所有的信息,都存在于ViewPagerState中。
我们还是先来实现跟之前ViewPagerStateless一样的效果。
class ViewPagerState extends State<ViewPagerStateful> {
var imgs = [
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-02.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-03.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-04.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-05.png",
"https://i1.mifile.cn/f/i/2019/micc9/summary/specs-06.png"
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ViewPager")),
body: PageView(
children: <Widget>[
Image.network(imgs[0]),
Image.network(imgs[1]),
Image.network(imgs[2]),
Image.network(imgs[3]),
Image.network(imgs[4]),
],
),
);
}
}
run一下,就发现,跟之前的效果完全一样。
接下来,我们要进行事件的监听,和viewpager内容的更改。
翻看上面代码发现,多数均为模版代码,仅有ViewPagerState内有很多内容。
所以,理所当然,点击事件也要在ViewPagerState中处理。
在ViewPagerState中新建方法,用来处理点击:
这里要用setState这个Flutter提供给我们的用于变更数据的方法,若不写这个包裹,则变化无效。
void changeImg(int pos) {
setState(() {
imgs[pos] = "https://i1.mifile.cn/f/i/2019/micc9/summary/specs-08.png";
});
}
在ViewPagerState中新建方法,用于监听滑动页面变更:
void onPageChanged(int pos) {
print("当前是第$pos页");
}
接下来,改造ViewPagerState的build方法,用于关联起来。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ViewPager")),
body: PageView(
children: <Widget>[
Image.network(imgs[0]),
Image.network(imgs[1]),
Image.network(imgs[2]),
Image.network(imgs[3]),
GestureDetector(
onTap: () => changeImg(4), child: Image.network(imgs[4]))
],
onPageChanged: onPageChanged,
),
);
}
这里说一下为什么要用() =>
这个是dart语法,若不用,则相当于直接执行changeImg(4)
,这样会在我们并没有点击时就会调用,这是不符合要求的。
Image本身不含有点击事件,需要用GestureDetector包裹。
这时候就可以run了。当我们切换页面,log就会打印出来,点击最后一页的图片就会更新图片。