需求分析
- 需要添加一组子控件
- 支持选中/未选中分别显示
- 支持点击事件回调
这里我们先使用Row实现一个LineIndicator
import 'package:flutter/material.dart';
class LinePageIndicator extends StatelessWidget {
final int count;
final int currentIndex;
final Color normalColor;
final Color selectColor;
final double width;
final double height;
final double padding;
final ValueChanged onItemTap;
LinePageIndicator({
Key key,
@required this.count,
@required this.normalColor,
@required this.selectColor,
@required this.currentIndex,
this.width : 16.0,
this.height : 6.0,
this.padding : 6.0,
this.onItemTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var container = Container(
decoration: BoxDecoration(
),
height: height,
width: width * count + padding * (count + 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: getChildren(),
),
);
return container;
}
List<Widget> getChildren() {
List<Widget> children = [];
for (int i = 0; i < count; i++) {
var colorVal = (i == currentIndex ? this.selectColor : this.normalColor);
children.add(GestureDetector(
child: Container(
width: width,
height: height,
decoration: BoxDecoration(
color: colorVal,
shape: BoxShape.rectangle,
),
),
onTap: () {
onItemTap(i);
},
));
}
return children;
}
}
这样就实现了一个Indicator.
如果我们要一个CircleIndicator又的重写大部分逻辑, 仅仅是形状改变以及区域计算变了.
这里我们可以抽离出一个基类, 使用ListView模式, 只用渲染一个子项目, 以及实现宽高的计算.
抽离出的代码如下:
import 'package:flutter/material.dart';
abstract class CustomPageIndicator extends StatelessWidget {
final int count;
final int currentIndex;
final ValueChanged onItemTap;
final Axis scrollDirection;
CustomPageIndicator({
Key key,
@required this.count,
this.currentIndex : 0,
this.scrollDirection,
this.onItemTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var container = Container(
height: scrollDirection == Axis.horizontal ? getHeight() : getWidth(),
width: scrollDirection == Axis.horizontal ? getWidth() : getHeight(),
child: getItems(),
);
return container;
}
Widget getItems() {
return ListView.builder(
itemCount: count,
scrollDirection: scrollDirection,
itemBuilder: (context, i) => GestureDetector(
child: renderRow(i),
onTap: () {
onItemTap(i);
},
),
);
}
Widget renderRow(i);
double getHeight();
double getWidth();
}
接着我们继承CustomPageIndicator实现一个CircleIndicator:
import 'package:app2/widgets/indicator/CustomPageIndicator.dart';
import 'package:flutter/material.dart';
class CirclePageIndicator extends CustomPageIndicator {
final Color normalColor;
final Color selectColor;
final double size;
final double padding;
CirclePageIndicator({
Key key,
int count,
int currentIndex,
ValueChanged onItemTap,
Axis scrollDirection : Axis.vertical,
this.padding : 2.0,
@required this.normalColor,
@required this.selectColor,
this.size : 12.0,
}) : super(key: key, count: count, currentIndex: currentIndex, onItemTap: onItemTap, scrollDirection: scrollDirection);
@override
Widget renderRow(i) {
var colorVal = (i == currentIndex ? this.selectColor : this.normalColor);
return Padding(
padding: EdgeInsets.all(padding),
child: Container(
width: size,
height: size,
decoration: BoxDecoration(
color: colorVal,
shape: BoxShape.circle,
),
),
);
}
double getHeight() {
return size + padding*2;
}
double getWidth() {
return size * count + padding * count * 2;
}
}
这样我们就只需要简单编写就完成需求了.
调用代码:
import 'package:app2/widgets/indicator/CirclePageIndicator.dart';
import 'package:app2/widgets/indicator/LinePageIndicator.dart';
import 'package:flutter/material.dart';
class BannerView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return BannerViewState();
}
}
class BannerViewState extends State<BannerView> {
PageController pageController = PageController();
int curIndex = 0;
var data = ['1', '2', '3', '4', '5', '6', '7'];
@override
Widget build(BuildContext context) {
return Stack(
children: [
getPages(),
Padding(
padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Align(
alignment: Alignment.topCenter,
child: getTopIndicator(),
),
),
Padding(
padding: EdgeInsets.fromLTRB(20.0, 0.0, 0.0, 0.0),
child: Align(
alignment: Alignment.centerLeft,
child: getLeftIndicator(),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 20.0),
child: Align(
alignment: Alignment.bottomCenter,
child: getBottomIndicator(),
),
),
],
);
}
Widget getTopIndicator() {
return LinePageIndicator(
count: data.length,
currentIndex: curIndex,
normalColor: Colors.red,
selectColor: Colors.yellow,
onItemTap: (index) {
pageController.jumpToPage(index);
},
);
}
Widget getLeftIndicator() {
return CirclePageIndicator(
scrollDirection: Axis.vertical,
count: data.length,
currentIndex: curIndex,
normalColor: Colors.red,
selectColor: Colors.yellow,
onItemTap: (index) {
pageController.jumpToPage(index);
},
);
}
Widget getBottomIndicator() {
return CirclePageIndicator(
scrollDirection: Axis.horizontal,
count: data.length,
currentIndex: curIndex,
normalColor: Colors.red,
selectColor: Colors.yellow,
onItemTap: (index) {
pageController.jumpToPage(index);
},
);
}
Widget getPages() {
return PageView.custom(
onPageChanged: (index) {
setState(() {
curIndex = index;
});
},
controller: pageController,
childrenDelegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: 20.0,
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % data.length)],
child: Text('page $index'),
);
},
childCount: data.length
)
);
}
}
网友评论