




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】利用Flutter怎么实现一个走马灯布局
本篇文章给大家分享的是有关利用Flutter怎么实现一个走马灯布局,在下觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着在下一起来看看吧。创建首页首先创建一个IndexPage部件,这个部件用来放PageView,因为需要使用setState方法更新UI,所以它是stateful的。import
'package:flutter/material.dart';
class
IndexPage
extends
StatefulWidget
{
@override
_IndexPageState
createState()
=>
_IndexPageState();
}
class
_IndexPageState
extends
State<IndexPage>
{
@override
Widget
build(BuildContext
context)
{
return
Scaffold(
appBar:
AppBar(
elevation:
0.0,
backgroundColor:
Colors.white,
),
body:
Column(
children:
<Widget>[],
),
);
}
}然后在部件内申明一个_pageIndex变量用来保存当前显示的页面的index,在initState生命周期里面初始化一个PageController用来配置PageView部件。在body的Column里面创建一个PageView.builder,使用一个SizedBox部件指定PageView的高度,将controller设置为_pageController,在onPageChanged事件里将当前显示页面的index值赋值给_pageIndex变量。int
_pageIndex
=
0;
PageController
_pageController;
@override
void
initState()
{
super.initState();
_pageController
=
PageController(
initialPage:
0,
viewportFraction:
0.8,
);
}
body:
Column(
children:
<Widget>[
SizedBox(
height:
580.0,
child:
PageView.builder(
itemCount:
3,
pageSnapping:
true,
controller:
_pageController,
onPageChanged:
(int
index)
{
setState(()
{
_pageIndex
=
index;
});
},
itemBuilder:
(BuildContext
ctx,
int
index)
{
return
_buildItem(_pageIndex,
index);
},
),
),
],
),关键点:设置PageController的viewportFraction参数小于1,这个值是用来设置每个页面在屏幕上显示的比例,小于1的话,就可以在当前页面同时显示其它页面的内容了。///
The
fraction
of
the
viewport
that
each
page
should
occupy.
///
Defaults
to
1.0,
which
means
each
page
fills
the
viewport
in
the
scrolling
direction.
final
double
viewportFraction;实现_buildItem接着实现_buildItem方法,这个方法就是返回PageView.builder里每一个页面渲染的内容,第一个参数activeIndex是当前显示在屏幕上页面的index,第二个参数index是每一项自己的index。使用一个Center部件让内容居中显示,然后用一个AnimatedContainer添加页面切换时的高度变化的动画效果,切换页面的时候使用了setState方法改变了_pageIndex,Flutter重新绘制每一项。关键点在于判断当前页面是否为正在显示的页面,是的话它的高度就是500不是的话就是450。_buildItem(activeIndex,
index)
{
return
Center(
child:
AnimatedContainer(
curve:
Curves.easeInOut,
duration:
Duration(milliseconds:
300),
height:
activeIndex
==
index
?
500.0
:
450.0,
margin:
EdgeInsets.symmetric(vertical:
20.0,
horizontal:
10.0),
decoration:
BoxDecoration(
color:
heroes[index].color,
borderRadius:
BorderRadius.all(Radius.circular(12.0)),
),
child:
Stack(),
),
);
}
添加内容然后给AnimatedContainer添加每一项的内容child:
Stack(
fit:
StackFit.expand,
children:
<Widget>[
ClipRRect(
borderRadius:
BorderRadius.all(
Radius.circular(12.0),
),
child:
Iwork(
heroes[index].image,
fit:
BoxFit.cover,
),
),
Align(
alignment:
Alignment.bottomCenter,
child:
Row(
children:
<Widget>[
Expanded(
child:
Container(
padding:
EdgeInsets.all(12.0),
decoration:
BoxDecoration(
color:
Colors.black26,
borderRadius:
BorderRadius.only(
bottomRight:
Radius.circular(12.0),
bottomLeft:
Radius.circular(12.0),
),
),
child:
Text(
heroes[index].title,
textAlign:
TextAlign.center,
style:
TextStyle(
fontSize:
20.0,
fontWeight:
FontWeight.bold,
color:
Colors.white,
),
),
),
)
],
),
),
],
),实现指示器然后实现页面的指示器,创建一个PageIndicator部件,需要传入pageCount表示总页数,以及currentIndex表示当前显示的页数索引。把所有指示器放在一个Row部件里,判断当前指示器的index是否为正在显示页面的index,是的话显示较深的颜色。class
PageIndicator
extends
StatelessWidget
{
final
int
pageCount;
final
int
currentIndex;
const
PageIndicator(this.currentIndex,
this.pageCount);
Widget
_indicator(bool
isActive)
{
return
Container(
width:
6.0,
height:
6.0,
margin:
EdgeInsets.symmetric(horizontal:
3.0),
decoration:
BoxDecoration(
color:
isActive
?
Color(0xff666a84)
:
Color(0xffb9bcca),
shape:
BoxShape.circle,
boxShadow:
[
BoxShadow(
color:
Colors.black12,
offset:
Offset(0.0,
3.0),
blurRadius:
3.0,
),
],
),
);
}
List<Widget>
_buildIndicators()
{
List<Widget>
indicators
=
[];
for
(int
i
=
0;
i
<
pageCount;
i++)
{
indicators.add(i
==
currentIndex
?
_indicator(true)
:
_indicator(false));
}
return
indicators;
}
@override
Widget
build(BuildContext
context)
{
return
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children:
_buildIndicators(),
);
}
}添加PageIndicator到SizedBox下面封装Carousel最后的最后优化一下代码,把部件封装一下,让它成为一个单独的部件,创建一个Carousel部件,对外暴露items和height两个属性,分别配置数据和高度。class
Carousel
extends
StatefulWidget
{
final
List
items;
final
double
height;
const
Carousel({
@required
this.items,
@required
this.height,
});
@override
_CarouselState
createState()
=>
_CarouselState();
}
class
_CarouselState
extends
State<Carousel>
{
int
_pageIndex
=
0;
PageController
_pageController;
Widget
_buildItem(activeIndex,
index)
{
final
items
=
widget.items;
return
Center(
child:
AnimatedContainer(
curve:
Curves.easeInOut,
duration:
Duration(milliseconds:
300),
height:
activeIndex
==
index
?
500.0
:
450.0,
margin:
EdgeInsets.symmetric(vertical:
20.0,
horizontal:
10.0),
decoration:
BoxDecoration(
color:
items[index].color,
borderRadius:
BorderRadius.all(Radius.circular(12.0)),
),
child:
Stack(
fit:
StackFit.expand,
children:
<Widget>[
ClipRRect(
borderRadius:
BorderRadius.all(
Radius.circular(12.0),
),
child:
Iwork(
items[index].image,
fit:
BoxFit.cover,
),
),
Align(
alignment:
Alignment.bottomCenter,
child:
Row(
children:
<Widget>[
Expanded(
child:
Container(
padding:
EdgeInsets.all(12.0),
decoration:
BoxDecoration(
color:
Colors.black26,
borderRadius:
BorderRadius.only(
bottomRight:
Radius.circular(12.0),
bottomLeft:
Radius.circular(12.0),
),
),
child:
Text(
items[index].title,
textAlign:
TextAlign.center,
style:
TextStyle(
fontSize:
20.0,
fontWeight:
FontWeight.bold,
color:
Colors.white,
),
),
),
)
],
),
),
],
),
),
);
}
@override
void
initState()
{
super.initState();
_pageController
=
PageController(
initialPage:
0,
viewportFraction:
0.8,
);
}
@override
Widget
build(BuildContext
context)
{
return
Column(
children:
<Widget>[
Container(
height:
widget.height,
child:
PageView.builder(
pageSnapping:
true,
itemCount:
heroes.length,
controller:
_pageController,
onPageChanged:
(int
index)
{
setState(()
{
_pageIndex
=
index;
});
},
itemBuilder:
(BuildContext
ctx,
int
index)
{
return
_buildItem(_pageIndex,
index);
},
),
),
PageIndicator(_pageIndex,
widget.items.length),
],
);
}
}之后在IndexPage部件里就只用实例化一个Carousel了,同时由于IndexPage不用管理部件状态了,可以将它变成StatelessWidget。完整代码import
'package:flutter/material.dart';
class
Hero
{
final
Color
color;
final
String
image;
final
String
title;
Hero({
@required
this.color,
@required
this.image,
@required
this.title,
});
}
List
heroes
=
[
Hero(
color:
Color(0xFF86F3FB),
image:
"/images/lol/act/img/skin/big22009.jpg",
title:
'寒冰射手-艾希',
),
Hero(
color:
Color(0xFF7D6588),
image:
"/images/lol/act/img/skin/big39006.jpg",
title:
'刀锋舞者-艾瑞莉娅',
),
Hero(
color:
Color(0xFF4C314D),
image:
"/images/lol/act/img/skin/big103015.jpg",
title:
'九尾妖狐-阿狸',
),
];
class
Carousel
extends
StatefulWidget
{
final
List
items;
final
double
height;
const
Carousel({
@required
this.items,
@required
this.height,
});
@override
_CarouselState
createState()
=>
_CarouselState();
}
class
_CarouselState
extends
State<Carousel>
{
int
_pageIndex
=
0;
PageController
_pageController;
Widget
_buildItem(activeIndex,
index)
{
final
items
=
widget.items;
return
Center(
child:
AnimatedContainer(
curve:
Curves.easeInOut,
duration:
Duration(milliseconds:
300),
height:
activeIndex
==
index
?
500.0
:
450.0,
margin:
EdgeInsets.symmetric(vertical:
20.0,
horizontal:
10.0),
decoration:
BoxDecoration(
color:
items[index].color,
borderRadius:
BorderRadius.all(Radius.circular(12.0)),
),
child:
Stack(
fit:
StackFit.expand,
children:
<Widget>[
ClipRRect(
borderRadius:
BorderRadius.all(
Radius.circular(12.0),
),
child:
Iwork(
items[index].image,
fit:
BoxFit.cover,
),
),
Align(
alignment:
Alignment.bottomCenter,
child:
Row(
children:
<Widget>[
Expanded(
child:
Container(
padding:
EdgeInsets.all(12.0),
decoration:
BoxDecoration(
color:
Colors.black26,
borderRadius:
BorderRadius.only(
bottomRight:
Radius.circular(12.0),
bottomLeft:
Radius.circular(12.0),
),
),
child:
Text(
items[index].title,
textAlign:
TextAlign.center,
style:
TextStyle(
fontSize:
20.0,
fontWeight:
FontWeight.bold,
color:
Colors.white,
),
),
),
)
],
),
),
],
),
),
);
}
@override
void
initState()
{
super.initState();
_pageController
=
PageController(
initialPage:
0,
viewportFraction:
0.8,
);
}
@override
Widget
build(BuildContext
context)
{
return
Column(
children:
<Widget>[
Container(
height:
widget.height,
child:
PageView.builder(
pageSnapping:
true,
itemCount:
heroes.length,
controller:
_pageController,
onPageChanged:
(int
index)
{
setState(()
{
_pageIndex
=
index;
});
},
itemBuilder:
(BuildContext
ctx,
int
index)
{
return
_buildItem(_pageIndex,
index);
},
),
),
PageIndicator(_pageIndex,
widget.items.length),
],
);
}
}
class
PageIndicator
extends
StatelessWidget
{
final
int
currentIndex;
final
int
pageCount;
const
PageIndicator(th
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 新解读《GB-T 31304-2014环氧涂层高强度钢丝拉索》
- 婚前房产单方名义购买协议6篇
- 老式钻机转让合同范本
- 拆除房屋合同范本
- 学校互换生合同范本
- 酒吧合作股份合同范本
- 阀块设计合同范本
- 抽水台班合同范本
- 代课教师劳务合同范本
- 啤酒销售促销合同范本
- 全球热泵产业发展报告2025
- 辅警考试真题(含答案)
- 商业地产项目数字化运营与客户体验提升策略研究报告
- 2025新疆天泽和达水务科技有限公司部分岗位社会招聘28人笔试模拟试题及答案解析
- 基于多元线性回归的国内旅游收入影响分析-以江西省为例
- 技术方案评审表-技术选型决策
- 水厂化验室知识培训课件
- 实验学校物业管理服务项目方案投标文件(技术方案)
- 2025个人房屋租赁合同范本下载
- 督脉刮痧配合刺血治疗急性乳腺炎
- 生物安全实验室管理体系文件
评论
0/150
提交评论