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;
     });
    },
   ),
  );
 }

 
}