Flutter学习-13
2024-11-21 12:44:57
Flutter组件封装
2764
一. StarRating
1.1功能
rating:必传参数,告诉Widget当前的评分。
maxRating:可选参数,最高评分,根据它来计算一个比例,默认值为10;
size:星星的大小,决定每一个star的大小;
unselectedColor:未选中星星的颜色(该属性是使用默认的star才有效);
selectedColor:选中星星的颜色(该属性也是使用默认的star才有效);
unselectedImage:定制未选中的star;
selectedImage:定义选中时的star;
count:展示星星的个数;
1.2. 实现思路分析
利用重叠功能
child: Stack( children: <Widget>[ Row(children: getUnSelectImage(), mainAxisSize: MainAxisSize.min,), Row(children: getSelectImage(), mainAxisSize: MainAxisSize.min,), ], ),
使用ClipRect定制CustomClipper进行裁剪
class MyRectClipper extends CustomClipper<Rect>{ finaldouble width; MyRectClipper({ this.width }); @override Rect getClip(Size size) { return Rect.fromLTRB(0, 0, width, size.height); } @override bool shouldReclip(MyRectClipper oldClipper) { return width != oldClipper.width; } }
使用MyRectClipper进行裁剪:
Widget leftStar = ClipRect( clipper: MyRectClipper(width: leftRatio * widget.size), child: widget.selectedImage, );
代码:
import 'package:flutter/material.dart'; class MKStarRating extends StatefulWidget { final double rating; final double maxRating; final int count; final double size; final Color unselectedColor; final Color selectedColor; final Widget unselectedImage; final Widget selectedImage; MKStarRating({ @required this.rating, this.maxRating = 10, this.count = 5, this.size = 30, this.unselectedColor = const Color(0xffbbbbbb), this.selectedColor = const Color(0xffff0000), Widget unselectedImage, Widget selectedImage, }):unselectedImage=unselectedImage??Icon(Icons.star_border, color: unselectedColor, size: size), selectedImage=selectedImage?? Icon(Icons.star, color: selectedColor, size: size) ; @override _MKStarRatingState createState() => _MKStarRatingState(); } class _MKStarRatingState extends State<MKStarRating> { @override Widget build(BuildContext context) { return Stack(children: [ Row(mainAxisSize: MainAxisSize.min, children: buildUnselectedStar()), Row(mainAxisSize: MainAxisSize.min, children: buildSelectedStar()), ]); } List<Widget> buildUnselectedStar() { return List.generate(widget.count, (index) { return widget.unselectedImage; }); } List<Widget> buildSelectedStar() { List<Widget> starts = []; final star = widget.selectedImage; double oneValue = widget.maxRating / widget.count; int entireCount = (widget.rating / oneValue).floor(); for (var i = 0; i < entireCount; i++) { starts.add(star); } double leftWidth= ((widget.rating/oneValue)-entireCount)*widget.size; print(leftWidth); final halfStar=ClipRect( clipper:MKStarClipper(leftWidth) , child: star,); starts.add(halfStar); return starts; } } class MKStarClipper extends CustomClipper<Rect>{ double width; MKStarClipper(this.width); @override Rect getClip(Size size) { return Rect.fromLTRB(0, 0, this.width, size.height); } @override bool shouldReclip(CustomClipper<Rect> oldClipper){ return false; } }
主要难点是初始列表传值
二. DashedLine
2.1分割虚线功能
axis:确定虚线的方向;
dashedWidth:根据虚线的方向确定自己虚线的宽度;
dashedHeight:根据虚线的方向确定自己虚线的高度;
count:内部会根据设置的个数和宽高确定密度(虚线的空白间隔);
color:虚线的颜色,不多做解释;
2.2. 代码
import 'package:flutter/material.dart'; class MKDashedLine extends StatelessWidget{ final Axis axis; final double dashedWidth; final double dashedHeight; final int count; final Color color; MKDashedLine({ this.axis=Axis.horizontal, this.dashedWidth=1, this.dashedHeight=1, this.count=10, this.color=Colors.red, }); @override Widget build(BuildContext context){ return Flex(direction: axis, mainAxisAlignment: MainAxisAlignment.spaceBetween, children:List.generate(count, (_){ return SizedBox( width:dashedWidth, height:dashedHeight, child:DecoratedBox( decoration: BoxDecoration(color:color), ) ); }) ); } }
三. 底部TabBar
3.1. TabBar属性
currentIndex:当前选中哪一个item;
selectedFontSize:选中时的文本大小;
unselectedFontSize:未选中时的文本大小;
type:当item的数量超过2个时,需要设置为fixed;
items:放入多个BottomNavigationBarItem类型;
onTap:监听哪一个item被选中;
class BottomNavigationBar extends StatefulWidget { BottomNavigationBar({ Key key, @requiredthis.items, this.onTap, this.currentIndex = 0, this.elevation = 8.0, BottomNavigationBarType type, Color fixedColor, this.backgroundColor, this.iconSize = 24.0, Color selectedItemColor, this.unselectedItemColor, this.selectedIconTheme = const IconThemeData(), this.unselectedIconTheme = const IconThemeData(), this.selectedFontSize = 14.0, this.unselectedFontSize = 12.0, this.selectedLabelStyle, this.unselectedLabelStyle, this.showSelectedLabels = true, bool showUnselectedLabels, }) }
使用IndexedStack来管理多个页面的切换:
body: IndexedStack( index: _currentIndex, children: <Widget>[ Home(), Subject(), Group(), Mall(), Profile() ],
3.2. TabBar代码实现
import 'package:flutter/material.dart'; import '../home/home.dart'; import './widget.dart'; class MKMainPage extends StatefulWidget { @override _MKMainPageState createState() => _MKMainPageState(); } class _MKMainPageState extends State<MKMainPage> { int _currentIndex=0; @override Widget build(BuildContext context) { return Scaffold( body: IndexedStack( index: _currentIndex, children: <Widget>[ MKHomePage(), MKHomePage(), MKHomePage(), MKHomePage(), MKHomePage(), ], ), bottomNavigationBar: BottomNavigationBar( type: BottomNavigationBarType.fixed, currentIndex: _currentIndex, items: [ MKBottomBarItem('home','首页'), MKBottomBarItem('subject','书阴影'), MKBottomBarItem('group','小组'), MKBottomBarItem('mall','事集'), MKBottomBarItem('profile','我的'), ], onTap: (index){ print(index); setState(() { _currentIndex=index; }); }, ), ); } }