Flutter星級評選

Ady Cheng發表於2020-03-18

1.效果圖

Flutter星級評選

2.設計思路

  • 確定使用Stack疊加效果主件,下面採用空(☆),上面疊加實心的(★).
  • 對外提供以下屬性讓外界設定:
                       
                        1.選中的顏色
                        2.未選中的顏色
                        3.星星總個數
                        4.平分最大值
                        5.當前平分值
                        6.星星的圖片

3.程式碼實現

1.建立MaterialApp

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter Demo",
      theme:
          ThemeData(primaryColor: Colors.blue, splashColor: Colors.transparent),
      home: Scaffold(
        appBar: AppBar(
          title: Text("StarDemo"),
        ),
        body: Center(
          child: StarRating(
            rating: 6.8,
            count: 5,
          ),
        ),
      ),
    );
  }
}

2.建立Stack控制元件

class StarRating extends StatefulWidget {
  /*外界控制的引數*/
  final int count;
  final double rating;
  final double maxRating;
  final double size;
  final Color unselectedColor;
  final Color selectedColor;
  final Widget selectedImage;
  final Widget unselectedImage;

  /*必傳引數和預設值*/
  StarRating(
      {@required this.rating,
      this.count = 5,
      this.maxRating = 10,
      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
  _StarRatingState createState() => _StarRatingState();
}

class _StarRatingState extends State {
  @override
  Widget build(BuildContext context) {
    /*stack主件疊加實現*/
    return Stack(
      children: [
        /*選中的?和未選中的?*/
        Row(mainAxisSize: MainAxisSize.min, children: buildUnselectedStar()),
        Row(mainAxisSize: MainAxisSize.min, children: buildSelectedStar()),
      ],
    );
  }

3.未選中的星星

/*未選中?*/
  List buildUnselectedStar() {
    return List.generate(widget.count, (index) {
      return widget.unselectedImage;
    });
  }

4.選中的星星

/*選中的?*/
  List buildSelectedStar() {
    //1.建立star
    List stars = [];
    final star = widget.selectedImage;

    //構建填充滿的star
    double oneValue = widget.maxRating / widget.count; //每一個佔用幾分
    int entireCount = (widget.rating / oneValue).floor(); //不滿一個向下取整

    for (var i = 0; i < entireCount; i++) {
      stars.add(star);
    }

    /*構建部分填充star*/
    //個數減去整數個乘以一個寬頻(3.5-3)*30
    double leftwidth = ((widget.rating / oneValue) - entireCount) * widget.size;
    final partStar = ClipRect(
      child: star,
      clipper: StarClipper(leftwidth),
    );

    stars.add(partStar);

    //如果平分大於上限就裁剪
    if (stars.length > widget.count) {
      return stars.sublist(0, widget.count);
    }
    return stars;
  }
}

5.裁剪不滿一個星星

/*自己裁剪?*/
class StarClipper extends CustomClipper {
  double width;

  StarClipper(this.width);

  @override
  Rect getClip(Size size) {
    return Rect.fromLTRB(0, 0, width, size.height);
  }

  @override
  bool shouldReclip(CustomClipper oldClipper) {
    return false;
  }
}

相關文章