更新 CustomPaint 绘图

Update CustomPaint drawing

我对 CustomPainter 小部件有疑问。我想绘制一个工作正常的饼图,然后我添加了一个变量来绘制图表,直到它达到这个角度。现在我想为它设置动画,我使用了 Future.delayed 函数并在其中使用 setState 我想更新变量但不幸的是它不起作用。

我正在为网络开发。感谢您的帮助!

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:stats/data/listLanguages.dart';
import 'painter/pieChartPainter.dart';

class Chart extends StatefulWidget {
  ListLanguages listLanguages;

  Chart({ListLanguages listLanguages}) {
    if (listLanguages == null) {
      listLanguages = new ListLanguages();
    }

    this.listLanguages = listLanguages;
  }

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

class _ChartState extends State<Chart> {
  @override
  Widget build(BuildContext context) {
    List angles = widget.listLanguages.calcCounts();

    int angle = 0;
    Future.delayed(new Duration(seconds: 2), (){
      setState(() {
        angle = 360;
        print("test");
      });
    });

    return Column(
      children: [
        Spacer(flex: 2),
        Row(
          children: [
            Spacer(),
            CustomPaint(
              size: Size.square(400),
              painter: PieChartPainter(
                angles: angles,
                colors: new List()
                  ..add(Colors.green)
                  ..add(Colors.blue)
                  ..add(Colors.brown)
                  ..add(Colors.pink)
                  ..add(Colors.orange)
                  ..add(Colors.grey.shade700),
                angle: angle,
              ),
            ),
            Spacer(flex: 10),
          ],
        ),
        Spacer(flex: 3),
      ],
    );
  }
}
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math.dart' as vm;

class PieChartPainter extends CustomPainter {
  List angles, colors;
  int angle;

  PieChartPainter(
      {@required List angles, @required List colors, int angle: 360}) {
    this.angles = angles;
    this.colors = colors;
    this.angle = angle;
  }

  @override
  void paint(Canvas canvas, Size size) {
    Paint p = new Paint();
    double start = -90;
    double tmp = 0;

    for (int i = 0; i < angles.length; i++) {
      if (i < 5) {
        p.color = colors[i];
      } else {
        p.color = colors[5];
      }

      if (tmp + angles[i] < angle) {
        canvas.drawArc(Rect.fromLTRB(0, 0, size.width, size.height),
            vm.radians(start), vm.radians(angles[i]), true, p);

        start = start + angles[i];
        tmp = tmp + angles[i];
      } else {
        double x = angle - tmp;
        canvas.drawArc(Rect.fromLTRB(0, 0, size.width, size.height),
            vm.radians(start), vm.radians(x), true, p);
        return;
      }
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

这是我必须创建饼图的完整代码

我不能使用你的代码所以我可以 运行 它(因为它只是一小部分)但你需要的是:

  1. 在你的状态下定义一个动画和动画控制器
  2. 用“AnimatedBuilder”包围您的 CustomPainter,它将使用此动画并在 2 秒内将 0 到 360 之间的值传递给您的 CustomPainter。

下面是一个带有评论的示例(您必须从中提取部分内容并将其放入您的小部件中)。


class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

// NOTE: You need to add "SingleTickerProviderStateMixin" for animation to work
class _TestState extends State<Test> with SingleTickerProviderStateMixin {
  Animation _animation; // Stores animation
  AnimationController _controller; // Stores controller

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 2),
    ); // Create a 2 second duration controller
    _animation = IntTween(begin: 0, end: 360)
        .animate(_controller); // Create the animation using controller with a tween from 0 to 360

    WidgetsBinding.instance.addPostFrameCallback((_) {
      _controller.forward(); // Start the animation when widget is displayed
    });
  }

  @override
  void dispose() {
    _controller.dispose(); // Don't forget to dispose your controller
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder( // AnimatedBuilder using the animation
      animation: _animation,
      builder: (context, _){
        return CustomPaint(
          size: Size.square(400),
          painter: PieChartPainter(
            angles: angles,
            colors: new List()
              ..add(Colors.green)
              ..add(Colors.blue)
              ..add(Colors.brown)
              ..add(Colors.pink)
              ..add(Colors.orange)
              ..add(Colors.grey.shade700),
            angle: _animation.value, // Pass _animation.value (0 to 360) as your angle
          ),
        );
      },
    );
  }
}


您可以复制粘贴 运行 下面的完整代码
在您的情况下,要使用 Future.delayed,您可以将逻辑从 build 移动到 initState 并使用 addPostFrameCallback
工作演示在 2、4、6 秒内更改 angle 并且 angle 为 150、250、360
代码片段

class _ChartState extends State<Chart> {
  int angle = 0;
  List angles;

  @override
  void initState() {
    angles = widget.listLanguages.calcCounts();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Future.delayed(Duration(seconds: 2), () {         
        setState(() {
          angle = 150;            
        });
      });
      Future.delayed(Duration(seconds: 4), () {         
        setState(() {
          angle = 250;            
        });
      });
      Future.delayed(Duration(seconds: 6), () {         
        setState(() {
          angle = 360;            
        });
      });
    });

工作演示

完整代码

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math.dart' as vm;

class ListLanguages {
  List calcCounts() {
    return [10.0, 20.0, 100.0, 150.0, 250.0, 300.0];
  }
}

class Chart extends StatefulWidget {
  ListLanguages listLanguages;

  Chart({ListLanguages listLanguages}) {
    if (listLanguages == null) {
      listLanguages = ListLanguages();
    }

    this.listLanguages = listLanguages;
  }

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

class _ChartState extends State<Chart> {
  int angle = 0;
  List angles;

  @override
  void initState() {
    angles = widget.listLanguages.calcCounts();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Future.delayed(Duration(seconds: 2), () {
        print("delay");
        setState(() {
          angle = 150;
          print("test");
        });
      });
      Future.delayed(Duration(seconds: 4), () {
        print("delay");
        setState(() {
          angle = 250;
          print("test");
        });
      });
      Future.delayed(Duration(seconds: 6), () {
        print("delay");
        setState(() {
          angle = 360;
          print("test");
        });
      });
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Spacer(flex: 2),
        Row(
          children: [
            Spacer(),
            CustomPaint(
              size: Size.square(400),
              painter: PieChartPainter(
                angles: angles,
                colors: List()
                  ..add(Colors.green)
                  ..add(Colors.blue)
                  ..add(Colors.brown)
                  ..add(Colors.pink)
                  ..add(Colors.orange)
                  ..add(Colors.grey.shade700),
                angle: angle,
              ),
            ),
            Spacer(flex: 10),
          ],
        ),
        Spacer(flex: 3),
      ],
    );
  }
}

class PieChartPainter extends CustomPainter {
  List angles, colors;
  int angle;

  PieChartPainter(
      {@required List angles, @required List colors, int angle: 360}) {
    this.angles = angles;
    this.colors = colors;
    this.angle = angle;
  }

  @override
  void paint(Canvas canvas, Size size) {
    Paint p = Paint();
    double start = -90;
    double tmp = 0;

    for (int i = 0; i < angles.length; i++) {
      if (i < 5) {
        p.color = colors[i];
      } else {
        p.color = colors[5];
      }

      if (tmp + angles[i] < angle) {
        canvas.drawArc(Rect.fromLTRB(0, 0, size.width, size.height),
            vm.radians(start), vm.radians(angles[i]), true, p);

        start = start + angles[i];
        tmp = tmp + angles[i];
      } else {
        double x = angle - tmp;
        canvas.drawArc(Rect.fromLTRB(0, 0, size.width, size.height),
            vm.radians(start), vm.radians(x), true, p);
        return;
      }
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Chart(
        listLanguages: ListLanguages(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}