flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级
在之前的开发过程中,需要实现卡片轮播效果,但是卡片轮播需要中间大、两边小一些的效果,这里就使用到了Swiper。具体效果如视频所示
添加链接描述
这里需要的效果是中间大、两边小一些,中间的卡片在最上层,两边的卡片会被中间的卡片挡住一部分。所以需要处理一下Custom_layout样式中Widget层级关系。
在工程的pubspec.yaml中引入swiper
# 轮播图
flutter_swiper_null_safety: ^1.0.2
Swiper无限轮播
通过Swiper()来构建轮播图控件,可以同步不同的属性搭配不同的效果
默认效果
Container(
height: 200,
child: new Swiper(
itemBuilder: (BuildContext context,int index){
return new Image.network(imgs[index],fit: BoxFit.cover,);
},
itemCount: imgs.length,
pagination: new SwiperPagination(),//如果不填则不显示指示点
control: new SwiperControl(),//如果不填则不显示左右按钮
),
),
3D卡片滚动
Container(
height: 200,
child: new Swiper(
itemBuilder: (BuildContext context, int index) {
return new Image.network(imgs[index],fit: BoxFit.cover,);
},
itemCount: imgs.length,
viewportFraction: 0.8,
scale: 0.9,
),
),
无限卡片堆叠
Container(
height: 200,
child: new Swiper(
itemBuilder: (BuildContext context, int index) {
return new Image.network(imgs[index],fit: BoxFit.cover,);
},
itemCount: imgs.length,
itemWidth: 300.0,
layout: SwiperLayout.STACK,
),
),
无限卡片堆叠2
Container(
height: 200,
child: new Swiper(
itemBuilder: (BuildContext context, int index) {
return new Image.network(imgs[index],fit: BoxFit.cover,);
},
itemCount: imgs.length,
itemWidth: 300.0,
itemHeight: 300.0,
layout: SwiperLayout.TINDER,
),
),
自定义效果
Container(
height: 200,
child: new Swiper(
layout: SwiperLayout.CUSTOM,
customLayoutOption: new CustomLayoutOption(
startIndex: -1,
stateCount: 3
).addRotate([
-45.0/180,
0.0,
45.0/180
]).addTranslate([
new Offset(-370.0, -40.0),
new Offset(0.0, 0.0),
new Offset(370.0, -40.0)
]),
itemWidth: 300.0,
itemHeight: 200.0,
itemBuilder: (context, index) {
return new Image.network(imgs[index],fit: BoxFit.cover,);
},
itemCount: imgs.length),
)
需要的效果是中间大、两边小一些,中间的卡片在最上层,两边的卡片会被中间的卡片挡住一部分
这里使用的是SwiperLayout.CUSTOM,
这里就需要查看源码,更改Custom_layout样式中Widget层级关系,更改Stack的子Widget层级关系,需要调整中间的卡片在最上层。
找到Custom_layout.dart的源码,找到Widget _buildAnimation(BuildContext context, Widget? w)。
需要更改list,重新排列list
if (list.isNotEmpty) {
int length = list.length;
int mid = length~/2;
List transList = [];
for (int i = mid; i >= 0; i--) {
List subList = [];
for (int index = 0; index < length; index++) {
int abs = (index - mid).abs();
if (abs == i) {
subList.add(list[index]);
}
}
transList.addAll(subList);
}
print("transList:${transList}");
if (transList.isNotEmpty && transList.length == list.length) {
list = transList;
}
}
更改后的_buildAnimation代码如下
Widget _buildAnimation(BuildContext context, Widget? w) {
List list = [];
if (_animationCount != null) {
double? animationValue = _animation?.value;
for (int i = 0; i < _animationCount!; ++i) {
int realIndex = _currentIndex + i + (_startIndex ?? 0);
realIndex = realIndex % widget.itemCount;
if (realIndex < 0) {
realIndex += widget.itemCount;
}
if (animationValue != null) {
list.add(_buildItem(i, realIndex, animationValue));
}
}
}
if (list.isNotEmpty) {
int length = list.length;
int mid = length~/2;
List transList = [];
for (int i = mid; i >= 0; i--) {
List subList = [];
for (int index = 0; index < length; index++) {
int abs = (index - mid).abs();
if (abs == i) {
subList.add(list[index]);
}
}
transList.addAll(subList);
}
print("transList:${transList}");
if (transList.isNotEmpty && transList.length == list.length) {
list = transList;
}
}
return new GestureDetector(
behavior: HitTestBehavior.opaque,
onPanStart: _onPanStart,
onPanEnd: _onPanEnd,
onPanUpdate: _onPanUpdate,
child: new ClipRect(
child: new Center(
child: _buildContainer(list),
),
),
);
}
需要实现效果的时候,我们需要使用Swiper的custom,使用CustomLayoutOption添加addScale和addOpacity以及addTranslate来确定不同的卡片的缩放大小、透明度、以及offset
代码如下
Swiper(
autoplay: true,
layout: SwiperLayout.CUSTOM,
customLayoutOption:
CustomLayoutOption(startIndex: 0, stateCount: 5)
..addScale([
0.6,
0.8,
1.0,
0.8,
0.6,
], Alignment.center)
..addOpacity([
1.0,
1.0,
1.0,
1.0,
1.0,
])
..addTranslate([
Offset(-180.0, 0),
Offset(-80.0, 0),
Offset(0.0, 0.0),
Offset(80.0, 0),
Offset(180.0, 0),
]),
itemWidth: 230.0,
itemHeight: 230.0,
itemBuilder: (context, index) {
return SwiperCard(imageUrl: imageUrls[index]);
},
itemCount: imageUrls.length,
)
页面的完整代码如下
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart';
class SwiperPage extends StatefulWidget {
const SwiperPage({super.key});
@override
State createState() => _SwiperPageState();
}
class _SwiperPageState extends State {
List imageUrls = [];
@override
void initState() {
// TODO: implement initState
imageUrls = [
"https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192142_ff632.thumb.1000_0.jpeg_webp",
"https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192143_f4355.thumb.1000_0.jpeg_webp",
"https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192146_0aaf2.thumb.1000_0.jpeg_webp",
"https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192148_357ff.thumb.1000_0.jpeg_webp",
"https://d-ssl.dtstatic.com/uploads/blog/202301/08/20230108192149_92c71.thumb.1000_0.jpeg_webp"
];
super.initState();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: const Text('SwiperPage'),
),
body: Container(
width: screenSize.width,
height: screenSize.height,
child: Stack(
alignment: Alignment.center,
children: [
Swiper(
autoplay: true,
layout: SwiperLayout.CUSTOM,
customLayoutOption:
CustomLayoutOption(startIndex: 0, stateCount: 5)
..addScale([
0.6,
0.8,
1.0,
0.8,
0.6,
], Alignment.center)
..addOpacity([
1.0,
1.0,
1.0,
1.0,
1.0,
])
..addTranslate([
Offset(-180.0, 0),
Offset(-80.0, 0),
Offset(0.0, 0.0),
Offset(80.0, 0),
Offset(180.0, 0),
]),
itemWidth: 230.0,
itemHeight: 230.0,
itemBuilder: (context, index) {
return SwiperCard(imageUrl: imageUrls[index]);
},
itemCount: imageUrls.length,
)
],
),
),
);
}
}
class SwiperCard extends StatelessWidget {
const SwiperCard({
super.key,
required this.imageUrl,
});
final String imageUrl;
@override
Widget build(BuildContext context) {
return Container(
width: 230,
height: 230,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10),
),
border: Border.all(
color: Color(0xFF5C6BC0),
style: BorderStyle.solid,
width: 3,
),
boxShadow: [
BoxShadow(
color: Color(0xFFE8EAF6),
offset: Offset(0, -5),
blurRadius: 10,
)
],
),
child: Stack(alignment: Alignment.center, children: [
Positioned(
top: 0,
child: Image.network(
imageUrl,
width: 230,
height: 230,
),
),
]),
);
}
}
最终实现了效果。
flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级
学习记录,每天不停进步。