custom_banner.dart 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. /// Description: custom banner
  4. /// Time : 07/17/2023 Monday
  5. /// Author : liuyuqi.gov@msn.cn
  6. class CustomBanner extends StatefulWidget {
  7. final List<String> _images;
  8. final double height;
  9. final ValueChanged<int> onTap;
  10. final Curve curve;
  11. const CustomBanner(
  12. this._images, {super.key,
  13. this.height = 200,
  14. required this.onTap,
  15. this.curve = Curves.linear,
  16. });
  17. @override
  18. _CustomBannerState createState() => _CustomBannerState();
  19. }
  20. class _CustomBannerState extends State<CustomBanner> {
  21. late PageController _pageController;
  22. late int _curIndex;
  23. late Timer _timer;
  24. @override
  25. void initState() {
  26. super.initState();
  27. _curIndex = widget._images.length * 5;
  28. _pageController = PageController(initialPage: _curIndex);
  29. _initTimer();
  30. }
  31. @override
  32. Widget build(BuildContext context) {
  33. return Stack(
  34. alignment: Alignment.bottomCenter,
  35. children: [
  36. _buildPageView(),
  37. _buildIndicator(),
  38. ],
  39. );
  40. }
  41. Widget _buildIndicator() {
  42. var length = widget._images.length;
  43. return Positioned(
  44. bottom: 10,
  45. child: Row(
  46. children: widget._images.map((s) {
  47. return Padding(
  48. padding: const EdgeInsets.symmetric(horizontal: 3.0),
  49. child: ClipOval(
  50. child: Container(
  51. width: 8,
  52. height: 8,
  53. color: s == widget._images[_curIndex % length]
  54. ? Colors.white
  55. : Colors.grey,
  56. ),
  57. ),
  58. );
  59. }).toList(),
  60. ),
  61. );
  62. }
  63. Widget _buildPageView() {
  64. var length = widget._images.length;
  65. return SizedBox(
  66. height: widget.height,
  67. child: PageView.builder(
  68. controller: _pageController,
  69. onPageChanged: (index) {
  70. setState(() {
  71. _curIndex = index;
  72. if (index == 0) {
  73. _curIndex = length;
  74. _changePage();
  75. }
  76. });
  77. },
  78. itemBuilder: (context, index) {
  79. return GestureDetector(
  80. onPanDown: (details) {
  81. _cancelTimer();
  82. },
  83. onTap: () {
  84. ScaffoldMessenger.of(context).showSnackBar(
  85. SnackBar(
  86. content: Text('当前 page 为 ${index % length}'),
  87. duration: const Duration(milliseconds: 500),
  88. ),
  89. );
  90. },
  91. child: Image.asset(
  92. widget._images[index % length],
  93. fit: BoxFit.cover,
  94. ),
  95. );
  96. },
  97. ),
  98. );
  99. }
  100. /// 点击到图片的时候取消定时任务
  101. _cancelTimer() {
  102. _timer.cancel();
  103. _initTimer();
  104. }
  105. /// 初始化定时任务
  106. _initTimer() {
  107. _timer = Timer.periodic(const Duration(seconds: 3), (t) {
  108. _curIndex++;
  109. _pageController.animateToPage(
  110. _curIndex,
  111. duration: const Duration(milliseconds: 300),
  112. curve: Curves.linear,
  113. );
  114. });
  115. }
  116. /// 切换页面,并刷新小圆点
  117. _changePage() {
  118. Timer(const Duration(milliseconds: 350), () {
  119. _pageController.jumpToPage(_curIndex);
  120. });
  121. }
  122. }