Schwusch / widget_arrows

Draw arrows between widgets in Flutter
https://pub.dev/packages/widget_arrows
MIT License
145 stars 14 forks source link

Draw issue #4

Closed pgulegin closed 1 year ago

pgulegin commented 4 years ago

Hello, great package!

But, I am having a slight issue with it. It appears that if you are using the arrows in certain scrollable views, the arrows are not updating their location correctly.

For example, if you check on the 3rd tab view, the arrows are missing. But, if you do a hot reload while on the 3rd tab, they will appear. Then, you will notice that they will not scroll with the view correctly.

The same problem occurs regardless of where you place the initial ArrowContainer widget.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  // Controllers.
  TabController _controller;

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

    _controller = TabController(
      length: 5,
      vsync: this,
    );
  }

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

    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ArrowContainer(
      child: Scaffold(
        body: SafeArea(
          child: TabBarView(
            controller: _controller,
            children: [
              Container(
                color: Colors.red,
              ),
              Container(
                color: Colors.blue,
              ),
              Container(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    ArrowElement(
                      id: '1',
                      targetId: '2',
                      color: Colors.black,
                      child: Text(
                        '1',
                      ),
                    ),
                    ArrowElement(
                      id: '2',
                      targetId: '3',
                      color: Colors.black,
                      child: Text(
                        '2',
                      ),
                    ),
                    ArrowElement(
                      id: '3',
                      targetId: '1',
                      color: Colors.black,
                      child: Text(
                        '3',
                      ),
                    ),
                  ],
                ),
              ),
              Container(
                color: Colors.green,
              ),
              Container(
                color: Colors.brown,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Thank you.

Schwusch commented 4 years ago

Hi! Thank you for the feedback. It seems like this appear in a couple of scenarios, like scrolling/navigation, and is not correct until something else triggers a repaint. Usually user input or hot reload as you mention. I don't know why the framework isn't rasterizing the repaint, but it can be some cache peculiarity for performance reasons. I don't know how to tell the framework that the CustomPaint is important and should be rastered every time it paints.

Suggestions are welcome.

pgulegin commented 4 years ago

I haven't looked into a permanent solution yet, but I got around the issue by calling a setState in my animation controller and setting shouldRepaint to always true.

Inside initState()

    _controller.animation.addListener(() {
      if (mounted) setState(() {});
    });

Inside _ArrowPainter

  @override
  bool shouldRepaint(_) {
    return true;
  }
Schwusch commented 4 years ago

Does either fix work on its own or is both needed? Both are potentially expensive, but if there's no other way...

pgulegin commented 4 years ago

In my case, both are needed. It is expensive, but I'm using it on a pretty minor part of the application. So, I am not too worried right now. It would be nice to figure out how to efficiently use this for the future though.

Schwusch commented 1 year ago

I just released version 0.4.0 that might fix the problem. I'll close the issue for now, but if the problem persists I can reopen.