flutter開發(fā)技巧自定頁面指示器PageIndicator詳解
一、來源
項(xiàng)目中遇到多個需要自定義輪播圖指示器的需求,封裝成基礎(chǔ)組件方便復(fù)用;
原理是通過 ValueListenableBuilder 實(shí)時監(jiān)聽輪播圖的當(dāng)前索引,然后更新指示器組件,達(dá)到最終效果;
二、效果

三、源碼實(shí)現(xiàn)
1、flutter_swiper_null_safety 使用示例:
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;//圖片鏈接數(shù)組
@override
Widget build(BuildContext context) {
dynamic arguments = ModalRoute.of(context)!.settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text(widget.title ?? "$widget"),
),
body: _buildSwiper()
);
}
///創(chuàng)建子項(xiàng)
_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,
// );
// },
)
],
)
),
);
}
2、PageIndicatorWidget 指示器源碼:
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);
/// 當(dāng)前頁面索引
ValueNotifier<int> currentPage;
EdgeInsetsGeometry? margin;
/// item數(shù)量
int itemCount;
/// 每個item尺寸(最好用固定寬度除以個數(shù),避免總寬度溢出)
Size itemSize;
/// 自定義每個item
PageIndicatorItemWidgetBuilder? itemBuilder;
/// 默認(rèn)顏色
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;
}
}
三、總結(jié)
此組件封裝也秉承最簡實(shí)現(xiàn),不超過百行代碼。開發(fā)工作中,如果我們發(fā)現(xiàn)最佳實(shí)踐,即使它很小,也需要記錄下來,常年累月下來機(jī)會自然而然擁有一套屬于自己的高效的組件庫。可以提高我們的開發(fā)效率,節(jié)約時間,讓工作變得輕松。
以上就是flutter開發(fā)技巧自定頁面指示器PageIndicator詳解的詳細(xì)內(nèi)容,更多關(guān)于flutter PageIndicator的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android實(shí)現(xiàn)類似網(wǎng)易新聞選項(xiàng)卡動態(tài)滑動效果
這篇文章主要介紹了Android實(shí)現(xiàn)類似網(wǎng)易新聞選項(xiàng)卡動態(tài)滑動效果的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-11-11
Android編程實(shí)現(xiàn)使用Intent傳輸包含自定義類的ArrayList示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)使用Intent傳輸包含自定義類的ArrayList,涉及Android對象序列化、反序列化、Intent數(shù)據(jù)傳輸?shù)认嚓P(guān)操作技巧,需要的朋友可以參考下2017-08-08
Android實(shí)現(xiàn)自定義帶刪除功能的EditText實(shí)例
本篇文章主要介紹了Android實(shí)現(xiàn)自定義帶刪除功能的EditText實(shí)例,非常具有實(shí)用價值,需要的朋友可以參考下2017-06-06
Android Messenger實(shí)現(xiàn)進(jìn)程間通信及其原理
這篇文章主要為大家詳細(xì)介紹了Android Messenger實(shí)現(xiàn)進(jìn)程間通信及其原理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-05-05
Android互聯(lián)網(wǎng)訪問圖片并在客戶端顯示的方法
這篇文章主要介紹了Android互聯(lián)網(wǎng)訪問圖片并在客戶端顯示的方法,結(jié)合實(shí)例分析了Android處理圖片的技巧,并附帶了Android的URL封裝類,網(wǎng)絡(luò)連接封裝類與輸出流封裝類,需要的朋友可以參考下2015-12-12
Android中使用GridView進(jìn)行應(yīng)用程序UI布局的教程
GridView即平常我們見到的類似九宮格的矩陣型布局,只不過默認(rèn)不帶分割線,這里我們就從基礎(chǔ)開始來看一下Android中使用GridView進(jìn)行應(yīng)用程序UI布局的教程2016-06-06

