flutter 评分星星组件的简单封装

·  阅读 133
flutter 评分星星组件的简单封装

flutter 评分星星组件的简单封装

import 'dart:math';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('评分组件'),
      ),
      body: HomeContent(),
    );
  }
}

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StartRating(count: 10,);
  }
}


class StartRating extends StatefulWidget {

  final double rating;  // 评分
  final double maxRating; // 总分
  final int count;  // 个数
  final double size;  // item的大小
  final Color unselectedColor;
  final Color selectColor;
  final Widget unselectedImage;
  final Widget selectedImage;
  // 哪些是必传的 哪些有默认值
  StartRating({
    @required this.rating,
    this.maxRating = 10,  //  默认为10
    this.count = 5,
    this.size = 30,
    this.unselectedColor = const Color(0xffbbbbbb),
    this.selectColor = Colors.red,
    Widget unselectedImage,
    Widget selectedImage
  }): unselectedImage = unselectedImage ?? Icon(Icons.star_border, color: unselectedColor, size: size,),
      selectedImage = selectedImage ?? Icon(Icons.star, color: unselectedColor, size: size,);

  @override
  _StartRatingState createState() => _StartRatingState();
}

class _StartRatingState extends State<StartRating> {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Row(children: buildUnselectedStar(), mainAxisSize: MainAxisSize.min,),
        Row(children: buildSelectedStar(),mainAxisSize: MainAxisSize.min,),
      ],
    );
  }

  List<Widget> buildUnselectedStar() {
    return List.generate(widget.count, (index) {
      return widget.unselectedImage;
    });
  }

  List<Widget> buildSelectedStar(){
    // 创建starts
    List<Widget> stars = [];
    final star = Icon(Icons.star, color: widget.unselectedColor, size: widget.size,);

    // 构建填充满的star
    double oneValue = widget.maxRating / widget.count; // 一个count的值  例如 Ranting是10分 一个star就是2分
    int entireCount = (widget.rating / oneValue).floor(); // 计算出 有几个 满星 例如 rating = 6 就会有5个满星
    for(var i = 0; i < entireCount; i++){
      stars.add(star);
    }

    // 构建部分填充的star 需要裁剪
    double leftWidth = ((widget.rating / oneValue) - entireCount) * widget.size;
    final section = ClipRect(
      clipper: StarClipper(leftWidth),
      child: star,
    );
    stars.add(section);
    // 防止 用户传的rating 大于 maxRating
    if(stars.length > widget.count){
      return stars.sublist(0,widget.count);
    }
    return stars;
  }
}

class StarClipper extends CustomClipper<Rect>{
  double width;

  StarClipper(this.width);

  @override
  Rect getClip(Size size) {   // 具体需要裁剪啥
    return Rect.fromLTRB(0, 0, width, size.height);
  }

  @override
  bool shouldReclip(StarClipper oldClipper) { // 重新裁剪
    return oldClipper.width != this.width;  // 如果旧的Clipper和当前新传入的width不同时需要裁剪
  }
}
复制代码
分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改