Как правильно разместить анимацию CustomPainter на экране? - PullRequest
1 голос
/ 15 марта 2020

На самом деле я пытался реализовать таймер. Таможенный художник получился довольно хорошим. Но когда я попытался поместить собственный художник в ряд или столбец, он переполняется. Пользовательская краска отображается только тогда, когда я явно определяю высоту и ширину контейнера. Теперь мне нужно добавить строку таймера в ряд с пользовательской краской, но она не работает. Высота и ширина контейнера занимают полный размер экрана, не позволяя отображать другие виджеты.

@override
  Widget build(BuildContext context) {
    double height = MediaQuery.of(context).size.height;
    double width = MediaQuery.of(context).size.width;

    return Scaffold(
      backgroundColor: Styles.primaryDarkBlue,
      body:  SafeArea(
              child: Container(
          height: height,
          width: width,
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: CustomPaint(
            painter: TimerBar(
                  animation: animation,
                )),
          ),
        ),
      ));
  }

Вот полный код.

import 'package:flutter/material.dart';


import 'package:focus7/styles.dart';

class Timer extends StatefulWidget {
  @override
  _TimerState createState() => _TimerState();
}

class _TimerState extends State<Timer> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation animation;

  String get timerString {
    Duration duration = controller.duration * controller.value;
    return "${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, "0")}";
  }

  @override
  void initState() {

    super.initState();
    controller = AnimationController(vsync: this, duration: Duration(seconds: 7));
    animation = Tween<double>(begin: 0.1, end: 1).animate(controller);
    controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    double height = MediaQuery.of(context).size.height;
    double width = MediaQuery.of(context).size.width;
    print(height);

    return Scaffold(
      backgroundColor: Styles.primaryDarkBlue,
      body:  SafeArea(
              child: Container(
          height: height,
          width: width,
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: CustomPaint(
            painter: TimerBar(
                  animation: animation,
                )),
          ),
        ),
      ));


  }
}

class TimerBar extends CustomPainter {
  final Gradient gradient = Styles.primaryGradient;
  final Color timerBarColor = Styles.primaryBlue;
  final Animation animation;

  TimerBar({this.animation}) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = new Paint()
      ..color = timerBarColor
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = 5;

    Rect rect = new Rect.fromLTWH(0, 0, size.width, size.height / 25);

    RRect rrectBorder = new RRect.fromRectAndRadius(rect, Radius.circular(50));
    canvas.drawRRect(rrectBorder, paint);

    paint.style = PaintingStyle.fill;
    paint.strokeWidth = 0;
    paint.shader = gradient.createShader(rect);

    Rect rectAnim = new Rect.fromLTWH(0, 0, size.width * animation.value, size.height / 25);
    RRect rrect = new RRect.fromRectAndRadius(rectAnim, Radius.circular(50));

    canvas.drawRRect(rrect, paint);

  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return false;
  }
}

здесь выводится :

enter image description here

, когда я пытался вложить в ряд:

return Scaffold(
        backgroundColor: Styles.primaryDarkBlue,
        body: SafeArea(
          child: Row(
            children: <Widget>[
              Container(
                height: height,
                width: width,
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: CustomPaint(
                      painter: TimerBar(
                    animation: animation,
                  )),
                ),
              ),
              AnimatedBuilder(animation: controller, builder: (context, child) {
                return Text(timerString,style: TextStyle(fontSize:24 ),);
              })
            ],
          ),
        ));

enter image description here

Ответы [ 2 ]

2 голосов
/ 15 марта 2020

Это можно сделать с помощью виджета Expanded и явной передачей ширины и высоты классу Timer ().

Я создал этот дартпад с кодом, чтобы вы могли его запустить (мне пришлось измените некоторые стили, чтобы он работал): http://dartpad.dev/eb69452a5c577d1a8286c6dd1a56e331

Во-первых, расширенный виджет, который я использовал в Scaffold:

return Scaffold(
  backgroundColor: Colors.yellow,
  body: SafeArea(
    child: Row(
      children: <Widget>[
        Expanded(  // <----------------------------------
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: CustomPaint(
              painter: TimerBar(
                width: width,
                height: height,
                animation: animation,
              ),
            ),
          ),
        ),
        AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            return Text(
              timerString,
              style: TextStyle(fontSize: 24),
            );
          },
        )
      ],
    ),
  ),
);

Это сработало, но высота и ширина панели таймера не были изменены в соответствии с медиазапросом, поэтому я сделал явные переменные для передачи в класс:

class TimerBar extends CustomPainter {
  final Gradient gradient = LinearGradient(
      begin: Alignment.topRight,
      end: Alignment.bottomLeft,
      colors: [Colors.blue, Colors.red]);

  final Color timerBarColor = Colors.blue;
  final Animation animation;
  final width;     // <----------------------------------
  final height;    // <----------------------------------

  TimerBar({this.animation, this.width, this.height}) // <----------------
      : super(repaint: animation);
...

, а затем я использовал эти значения ширины для ваших двух объектов прямоугольника:

Rect rect = new Rect.fromLTWH(0, 0, width, height / 25); // <-------------

RRect rrectBorder = new RRect.fromRectAndRadius(rect, Radius.circular(50));
canvas.drawRRect(rrectBorder, paint);

paint.style = PaintingStyle.fill;
paint.strokeWidth = 0;
paint.shader = gradient.createShader(rect);

Rect rectAnim =
    new Rect.fromLTWH(0, 0, width * animation.value, height / 25);  // <------------
RRect rrect = new RRect.fromRectAndRadius(rectAnim, Radius.circular(50));
1 голос
/ 15 марта 2020

Я нашел решение после многих проб и ошибок .... Код ниже выглядит нормально.

return Scaffold(
        backgroundColor: Styles.primaryDarkBlue,
        body: SafeArea(
          child: Padding(
            padding: const EdgeInsets.all(10),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Expanded(
                  flex: 5,
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: AnimatedBuilder(
                        animation: controller,
                        builder: (context, child) {
                          return CustomPaint(painter: TimerBar(animation: animation, height: height));
                        }),
                  ),
                ),
                Expanded(
                  flex: 1,
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: AnimatedBuilder(
                        animation: controller,
                        builder: (context, child) {
                          return Text(
                            timerString,
                            style: TextStyle(fontSize: 24, color: Styles.primaryWhite),
                          );
                        }),
                  ),
                )
              ],
            ),
          ),
        ));

вывод:

enter image description here

...