1

I have a CustomPainter like below and I want it to bind with a parent widget containing a ListView.builder how do I do that?
Expected Behaviour: the painter should paint as I scroll up or down.

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

class PlayerPainter extends CustomPainter {
  final Animation<double> animation;
  final Paint backgroundPaint;
  final Color bgColor;
  final Color thumbColor;
  final Paint sliderPaint;
  final Paint thumbPaint;

  PlayerPainter({this.animation, this.bgColor, this.thumbColor})
      : backgroundPaint = Paint()..color = bgColor,
        sliderPaint = Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = 3.0,
        thumbPaint = Paint()..color = thumbColor,
        super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    final value = animation.value;
    final radius = size.width * 0.5;
    final thumbRadius = 4.0;
    final rect = Rect.fromCircle(center: Offset(radius, size.height), radius: radius);
    final thumbPosX = radius + (radius * -cos(value * pi));
    final thumbPosY = (size.height - thumbRadius) + ((size.height - thumbRadius) * -sin(value * pi));
    sliderPaint.shader = LinearGradient(colors: [
      const Color(0xFFCC2B5E),
      const Color(0xFF753A88),
      const Color(0xFFCC2B5E),
      const Color(0xFF753A88),
    ]).createShader(rect);

    canvas.drawArc(rect, pi, pi, false, backgroundPaint);
    canvas.drawArc(rect, pi, value * pi, false, sliderPaint);
    canvas.drawCircle(Offset(thumbPosX, thumbPosY), thumbRadius, thumbPaint);
  }

  @override
  bool shouldRepaint(PlayerPainter oldDelegate) => true;
}

parent.dart

@override
  void initState() {
    _controller = AnimationController(vsync: this);
    _scrollController.addListener(() {
      setState(() {
        _controller = AnimationController(
          value: _scrollController.offset,
          duration: Duration(seconds: 0),
          vsync: this,
        );
      });
    });
}
PlayerView(
...
  controller: _controller,
  ),

════════ Exception caught by foundation library ════════════════════════════════════════════════════ _MusicScreenState is a SingleTickerProviderStateMixin but multiple tickers were created.

  • check `ScrollController` - it is `Listenable` so it can be passed to a `CustomPainter` as a `repaint` named parameter (`super(repaint: controller)`) – pskink Aug 30 '20 at 10:20
  • @pskink but how Do I pass in the value as well for `Animation`? – White Knife Aug 30 '20 at 10:46
  • pass both `Listenable`s and use `Listenable.merge` in `super(...)` - something like `Listenable.merge([l0, l1])` – pskink Aug 30 '20 at 10:56
  • This means that I have to create `Animation` but what I want is that the `animation` should be controlled by the `ScrollController` only. – White Knife Aug 30 '20 at 11:02
  • so don't need that animation if it is the same as current scroll position of your listview – pskink Aug 30 '20 at 11:18
  • But I need that `animation` inside the `void paint(Canvas canvas, Size size) ` – White Knife Aug 30 '20 at 11:20
  • https://pastebin.com/raw/nwv1pRtw – pskink Aug 30 '20 at 11:49
  • @pskink ScrollController attached to multiple scroll views – White Knife Aug 30 '20 at 11:58
  • so attach it to only one - single `ScrollController` cannot control multiple views – pskink Aug 30 '20 at 12:02
  • I am only using a single `ScrollController` – White Knife Aug 30 '20 at 12:06
  • i gave you a sample, working code in the top comment - just use it – pskink Aug 30 '20 at 12:08
  • now I am getting null point exception on the `ctrl.offset` – White Knife Aug 30 '20 at 12:12
  • `class Foo extends StatelessWidget { final controller = ScrollController(); @override Widget build(BuildContext context) { return CustomPaint( painter: MyPainter(controller), child: ListView( controller: controller, children: [ for(var i = 0; i < 64; i++) Text(' === item #$i', textScaleFactor: 2) ], ), ); } }` – pskink Aug 30 '20 at 12:20
  • Still the same ```The method 'toDouble' was called on null. Receiver: null Tried calling: toDouble()``` – White Knife Aug 30 '20 at 12:32
  • there is no `toDouble` method called in my code – pskink Aug 30 '20 at 12:34
  • I am using `controller.position.pixels` It is showing at that – White Knife Aug 30 '20 at 12:36
  • there is no no need for it: https://github.com/flutter/flutter/blob/c969b8af7b/packages/flutter/lib/src/widgets/scroll_controller.dart#L118 `double get offset => position.pixels;` just use `ctrl.offset / 10` as i did – pskink Aug 30 '20 at 12:42
  • But I am also using `controller.position.pixels / controller.position.maxScrollExtent` and It is also throwing NPE – White Knife Aug 30 '20 at 12:46
  • 1
    `@override void paint(Canvas canvas, Size size) { var cur = ctrl.offset; var max = ctrl.position.maxScrollExtent; print('0 <= $cur <= $max'); canvas.drawRect(Rect.fromLTWH(0, ctrl.offset / 10, 100, 100), Paint()..color = Colors.orange); }` works just fine – pskink Aug 30 '20 at 12:58

0 Answers0