目录一、来源二、效果三、源码实现1、Flutter_swiper_null_safety 使用示例:2、PageIndicatorWidget 指示器源码:三、总结一、来源 项目中
项目中遇到多个需要自定义轮播图指示器的需求,封装成基础组件方便复用;
原理是通过 ValueListenableBuilder 实时监听轮播图的当前索引,然后更新指示器组件,达到最终效果;
import 'package:flutter/material.dart';
import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart';
import 'package:flutter_templet_project/R.dart';
import 'package:flutter_templet_project/basicWidget/page_indicator_widget.dart';
import 'package:flutter_templet_project/extension/buildContext_extension.dart';
class FlutterSwiperIndicatorDemo extends StatefulWidget {
FlutterSwiperIndicatorDemo({ Key? key, this.title}) : super(key: key);
final String? title;
@override
_FlutterSwiperIndicatorDemoState createState() => _FlutterSwiperIndicatorDemoState();
}
class _FlutterSwiperIndicatorDemoState extends State<FlutterSwiperIndicatorDemo> {
ValueNotifier<int> currentIndex = ValueNotifier(0);
BorderRadius borderRadius = BorderRadius.all(Radius.circular(8));
final items = R.imgUrls;//图片链接数组
@override
Widget build(BuildContext context) {
dynamic arguments = ModalRoute.of(context)!.settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text(widget.title ?? "$widget"),
),
body: _buildSwiper()
);
}
///创建子项
_buildItem(context, index) {
final imgUrl = items[index];
return InkWell(
onTap: () => print(index),
child: Container(
padding: EdgeInsets.only(bottom: 0), //为了显示阴影
child: ClipRRect(
borderRadius: this.borderRadius,
child: Stack(
alignment: Alignment.center,
fit: StackFit.expand,
children: [
FadeInImage(
placeholder: AssetImage('images/img_placeholder.png',),
image: NetworkImage(imgUrl),
fit: BoxFit.cover,
),
],
),
),
),
);
}
_buildSwiper() {
return Container(
height: 200,
child: ClipRRect(
borderRadius: this.borderRadius,
child: Stack(
children: [
Swiper(
itemBuilder: (context, index) => _buildItem(context, index),
// indicatorLayout: PageIndicatorLayout.COLOR,
autoplay: this.items.length > 1,
loop: this.items.length > 1,
itemCount: this.items.length,
// pagination: this.items.length <= 1 ? null : SwiperPagination(),
// control: SwiperControl(),
// itemWidth: 200,
// viewportFraction: 0.6,
onIndexChanged: (index){
currentIndex.value = index;
}
),
// if (this.items.length > 1) buildPageIndicator(),
if (this.items.length > 1) PageIndicatorWidget(
currentIndex: currentIndex,
itemCount: this.items.length,
itemSize: Size(context.screenSize.width/ 4 / this.items.length, 2),
// itemBuilder: (isSelected, itemSize) {
// return Container(
// width: itemSize.width,
// height: itemSize.height,
// color: isSelected ? Colors.red : Colors.green,
// );
// },
)
],
)
),
);
}
import 'package:flutter/material.dart';
typedef PageIndicatorItemWidgetBuilder = Widget Function(bool isSelected, Size itemSize);
/// 轮播图指示器
class PageIndicatorWidget extends StatelessWidget {
PageIndicatorWidget({
Key? key,
this.margin = const EdgeInsets.only(bottom: 10),
required this.currentPage,
required this.itemCount,
this.nORMalColor = const Color(0x25ffffff),
this.selectedColor = Colors.white,
this.itemSize = const Size(8, 2),
this.itemBuilder,
this.hidesForSinglePage = true
}) : super(key: key);
/// 当前页面索引
ValueNotifier<int> currentPage;
EdgeInsetsGeometry? margin;
/// item数量
int itemCount;
/// 每个item尺寸(最好用固定宽度除以个数,避免总宽度溢出)
Size itemSize;
/// 自定义每个item
PageIndicatorItemWidgetBuilder? itemBuilder;
/// 默认颜色
Color? normalColor;
/// 选中颜色
Color? selectedColor;
/// 单页隐藏
bool hidesForSinglePage;
@override
Widget build(BuildContext context) {
if (this.hidesForSinglePage && this.itemCount == 1) {
return SizedBox();
}
return buildPageIndicator();
}
Widget buildPageIndicator() {
return Container(
margin: this.margin,
child: Align(
alignment: Alignment.bottomCenter,
child: ValueListenableBuilder(
valueListenable: this.currentPage,
builder: (BuildContext context, dynamic value, Widget? child) {
return Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: buildPageIndicatorItem(
currentIndex: this.currentPage.value,
normalColor: this.normalColor,
selectedColor: this.selectedColor,
),
);
},
),
),
);
}
List<Widget> buildPageIndicatorItem({
currentIndex: 0,
normalColor: const Color(0x25ffffff),
selectedColor: Colors.white,
}) {
List<Widget> list = List.generate(this.itemCount, (index) {
return this.itemBuilder != null ? this.itemBuilder!(currentIndex == index, this.itemSize) : ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(1)),
child: Container(
width: this.itemSize.width,
height: this.itemSize.height,
color: currentIndex == index ? selectedColor : normalColor,
),
);
});
return list;
}
}
此组件封装也秉承最简实现,不超过百行代码。开发工作中,如果我们发现最佳实践,即使它很小,也需要记录下来,常年累月下来机会自然而然拥有一套属于自己的高效的组件库。可以提高我们的开发效率,节约时间,让工作变得轻松。
以上就是flutter开发技巧自定页面指示器PageIndicator详解的详细内容,更多关于flutter PageIndicator的资料请关注编程网其它相关文章!
--结束END--
本文标题: flutter开发技巧自定页面指示器PageIndicator详解
本文链接: https://lsjlt.com/news/177793.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-21
2023-10-28
2023-10-28
2023-10-27
2023-10-27
2023-10-27
2023-10-27
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0