Flutter进阶—实现动画效果(四)

119 篇文章 9 订阅
82 篇文章 1416 订阅

在上一篇文章:Flutter进阶—实现动画效果(三)中,实现了一个随机高度、颜色的条形。这一篇文章我们会实现多个条形,同样是随机高度、颜色。

首先在bar.dart中创建BarChart类,并使用固定长度的Bar实例列表。我们将使用5个条形,表示一周的5个工作日。然后,我们需要将创建空白和随机实例的责任从Bar转移到BarChart。

import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
import 'dart:ui' show lerpDouble;
import 'dart:math';
import 'color_palette.dart';

class BarChart {
  static const int barCount = 5;
  final List<Bar> bars;

  BarChart(this.bars) {
    assert(bars.length == barCount);
  }

  factory BarChart.empty() {
    return new BarChart(
      /*
      List.filled(
        int length,
        E fill, {
          bool growable: false
        }
      )
      创建给定长度的固定长度列表,并用fill在每个位置初始化值
      length必须是非负整数
       */
      new List.filled(
        barCount,
        new Bar(0.0, Colors.transparent)
      )
    );
  }

  factory BarChart.random(Random random) {
    final Color color = ColorPalette.primary.random(random);
    return new BarChart(
      /*
      List.generate(
        int length,
        E generator(
          int index
        ), {
        bool growable: true
        }
      )
      创建给定长度的固定长度列表,并用generator创建的值在每个位置初始化值
      创建的列表是固定长度,除非growable为true
       */
      new List.generate(
        barCount,
        (i) => new Bar(
          random.nextDouble()*100.0,
          color
        )
      )
    );
  }

  static BarChart lerp(BarChart begin, BarChart end, double t) {
    return new BarChart(
      new List.generate(
        barCount,
        (i) => Bar.lerp(begin.bars[i], end.bars[i], t)
      )
    );
  }
}

class BarChartTween extends Tween<BarChart> {
  BarChartTween(BarChart begin, BarChart end) : super(begin: begin, end: end);

  @override
  BarChart lerp(double t) => BarChart.lerp(begin, end, t);
}

class Bar {
  Bar(this.height, this.color);
  final double height;
  final Color color;

  static Bar lerp(Bar begin, Bar end, double t) {
    return new Bar(
        lerpDouble(begin.height, end.height, t),
        Color.lerp(begin.color, end.color, t)
    );
  }
}

class BarTween extends Tween<Bar> {
  BarTween(Bar begin, Bar end) : super(begin: begin, end: end);

  @override
  Bar lerp(double t) => Bar.lerp(begin, end, t);
}

class BarChartPainter extends CustomPainter {
  static const barWidthFraction = 0.75;

  BarChartPainter(Animation<BarChart> animation)
      : animation = animation,
        super(repaint: animation);

  final Animation<BarChart> animation;

  @override
  void paint(Canvas canvas, Size size) {
    void drawBar(Bar bar, double x, double width, Paint paint) {
      paint.color = bar.color;
      canvas.drawRect(
        new Rect.fromLTWH(
          x,
          size.height-bar.height,
          width,
          bar.height
        ),
        paint
      );
    }

    /*
    Paint:Canvas绘制时使用的样式说明
      style:是否绘制内部的形状、形状的边缘或两者都有,默认为PaintingStyle.fill
     */
    final paint = new Paint()..style = PaintingStyle.fill;
    final chart = animation.value;
    //  每个条形占用的空间宽度
    final barDistance = size.width/(1+chart.bars.length);
    // 每个条形占用空间75%的宽度
    final barWidth = barDistance*barWidthFraction;
    // 用于计算每个条形的x坐标点
    var x = barDistance-barWidth/2;
    for (final bar in chart.bars) {
      drawBar(bar, x, barWidth, paint);
      x += barDistance;
    }
  }

  @override
  bool shouldRepaint(BarChartPainter old) => false;
}

BarChartPainter在条形之间均匀分配可用宽度,并使每个条形占用可用宽度的75%。接下来我们要更新main.dart,用BarChart、BarChartTween替换Bar、BarTween。

// ...
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  final random = new Random();
  AnimationController animation;
  BarChartTween tween;

  @override
  void initState() {
    super.initState();
    animation = new AnimationController(
        duration: const Duration(milliseconds: 300),
        vsync: this
    );
    tween = new BarChartTween(new BarChart.empty(), new BarChart.random(random));
    animation.forward();
  }

  @override
  void dispose() {
    animation.dispose();
    super.dispose();
  }

  void changeData() {
    setState(() {
      tween = new BarChartTween(
        tween.evaluate(animation),
        new  BarChart.random(random),
      );
      animation.forward(from: 0.0);
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
          child: new CustomPaint(
              size: new Size(200.0, 100.0),
              painter: new BarChartPainter(tween.animate(animation))
          )
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: changeData,
        child: new Icon(Icons.refresh),
      ),
    );
  }
}

现在应用程序的效果如下图:

这里写图片描述

未完待续~~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何小有

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值