Code Monkey home page Code Monkey logo

just_the_tooltip's Introduction

just_the_tooltip

just_the_tooltip gives you more flexibility over the Flutter standard Tooltip by allowing you to set arbitrary content. It also expands on their single axis layout algorithm to fit both vertically and horizontally. The tooltip can be positioned along any axis and will fall back to the opposite side if overflowed.

Breaking

  • Removed JustTheTooltip.entry named constructor in favor of dedicated widget JustTheTooltipEntry. This mirrors a change in the code that explicitly differentiates where and how tooltips are shown.

Getting Started

JustTheTooltip(
  child: Material(
    color: Colors.grey.shade800,
    shape: const CircleBorder(),
    elevation: 4.0,
    child: const Padding(
      padding: EdgeInsets.all(8.0),
      child: Icon(
        Icons.add,
        color: Colors.white,
      ),
    ),
  ),
  content: const Padding(
    padding: EdgeInsets.all(8.0),
    child: Text(
      'Bacon ipsum dolor amet kevin turducken brisket pastrami, salami ribeye spare ribs tri-tip sirloin shoulder venison shank burgdoggen chicken pork belly. Short loin filet mignon shoulder rump beef ribs meatball kevin.',
    ),
  ),
)

JustTheTooltip needs two arguments. The direct child widget and the content (of the tooltip). The child widget will be wrapped with a GestureDetector or MouseRegion that is responsible for showing and hiding the content. Further handling of the tooltip state can be managed explicitly through a controller:

If you'd like to create a controller to manage the state of the tooltip, you can do so by defining an instance of a JustTheController and pass it through to constructor.

final tooltipController = JustTheController();

child: JustTheTooltip(
  controller: tooltipController,
  // ...
)

void showTooltip() {
  controller.showTooltip();
}

The controller itself is a ValueNotifier that carries the open/close state of the tooltip. To listen to these changes, add a listener to your controller.

@override
void initState() {
  // Programatically display tooltip after two seconds
  Future.delayed(const Duration(seconds: 2), () {
    tooltipController.showTooltip(immediately: false);
  });

  tooltipController.addListener(() {
    // Prints the enum value of [TooltipStatus.isShowing] or [TooltipStatus.isHiding]
    print('controller: ${tooltipController.value}');
  });
}

If you'd like to simply react to open or close states, you can pass through onDismiss or onShow callbacks to the default constructor.

JustTheTooltip(
  onDismiss: () {
    // Maybe continue tutorial?
  },
  onShow: () {
    // Start animation?
  }
),

If you'd like to keep the user from dismissing the tooltip by clicking on the barrier, you can change barrierDismissible to true which means pressing on the scrim area will not immediately hide the tooltip.

Customization

  • Modal

You can further define how a Tooltip will show by defining the isModal property. A modal will only open through clicking on the child and close by clicking on the background area (referred to as the skrim here). A non-modal (the default) is a more traditional tooltip opens and closes on hovers.

Note, phone emulators do not implement mouse controls. To test hover states, use a browser.

The fallback used when no mouse region is present but isModal is false is to only open when long pressed.

  • Tail Builder

If you'd like a custom tail (the nub on the end dialog bubble) drawn on your tooltip, you can pass through your own tailBuilder. The JustTheInterface.defaultTailBuilder (default) shows how to simply draw and return a path for your custom tails:

Path defaultTailBuilder(Offset tip, Offset point2, Offset point3) {
  return Path()
    ..moveTo(tip.dx, tip.dy)
    ..lineTo(point2.dx, point2.dy)
    ..lineTo(point3.dx, point3.dy)
    ..close();
}

The library also provides a simple bezier curved tailbuilder JustTheInterface.defaultBezierTailBuilder.

  • ListViews

The tooltip should also work in lists and follow the target through scrolling. For even more consideration of the available space in ListViews, a ScrollController may be passed to the just_the_tooltip to give the layout algorithm a hint as to how much space is before and after the scroll axis. This allows tooltips that would otherwise overflow to use up space offscreen in one of the scroll directions.

  • Non-Overlay Tooltip

For use cases where the tooltip must be a part the widget tree rather than an overlay there is a JustTheTooltipEntry.

Scaffold(
  appBar: AppBar(title: const Text('It goes under me')),
  body: JustTheTooltipArea(
    builder: (context, tooltip, scrim) {
      return Stack(
        fit: StackFit.passthrough,
        children: [
          ListView.builder(
            itemCount: 30,
            itemBuilder: (context, index) {
              if (index == 15) {
                return JustTheTooltipEntry(
                  tailLength: 10.0,
                  preferredDirection: AxisDirection.down,
                  isModal: true,
                  margin: const EdgeInsets.all(20.0),
                  child: const Material(
                    color: Colors.blue,
                    shape: CircleBorder(),
                    elevation: 4.0,
                    child: Padding(
                      padding: EdgeInsets.all(8.0),
                      child: Icon(
                        Icons.touch_app,
                        color: Colors.white,
                      ),
                    ),
                  ),
                  content: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Container(
                        height: 120,
                        color: Colors.blue,
                        width: double.infinity,
                      ),
                      const SizedBox(height: 8),
                      const Text(
                        'Quia ducimus eius magni voluptatibus ut veniam ducimus. Ullam ab qui voluptatibus quos est in. Maiores eos ab magni tempora praesentium libero. Voluptate architecto rerum vel sapiente ducimus aut cumque quibusdam. Consequatur illo et quos vel cupiditate quis dolores at.',
                      ),
                    ],
                  ),
                );
              }

              return ListTile(title: Text('Item $index'));
            },
          ),
          // In the case of no scrim showing, this will return an SizedBox.shrink
          scrim,
          // In the case of no scrim showing, this will return an SizedBox.shrink
          tooltip,
        ],
      );
    },
  ),
);

This will give you the positioned tooltip and scrim (an empty gesture detector that catches tap events and closes the tooltip) for you to enter into the tree however you like. By doing this, you can make tooltips that are visually "under" other parts of the UI such as the appbar in the above example.

API subject to change.

Contributing

Issues and PRs welcome. Unless otherwise specified, all contributions to this lib will be under MIT license.

Help wanted

If you're interested in becoming a contributor with push rights please ping me and we can talk about how to get you started ! :)

just_the_tooltip's People

Contributors

anton-tarasiuk avatar caseycrogers avatar pavel-sulimau avatar piotrmitkowski avatar sgehrman avatar stargazing-dino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

just_the_tooltip's Issues

Breaks with RotatedBox

I don't know how to get a box that has a preferredSize that is larger in the vertical direction than the horizontal. This was to test that it worked in correctly constraining stuff.

However, I tried a RotatedBox and it looks like it doesn't swap the size? Not sure how but I got a width of like 68 for something that was obviously like 300. I don't know how you'd check if something was rotated either

This functionality probably belongs in dependentBox stuff but if it's not even being passed the actual information of the box it's positioning then I'm at a loss

Unhandled Exception: RenderFlex children have non-zero flex

I reported this previously, but have the problem again.

try a test like:

Listview
children: [
tooltip(
child: Row(children: [Text, Expanded(Text), Button])
)
]
)

The tooltip code doesn't like that expanded row.

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: RenderFlex children have non-zero flex but incoming width constraints are unbounded.
When a row is in a parent that does not provide a finite width constraint, for example if it is in a horizontal scrollable, it will try to shrink-wrap its children along the horizontal axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the horizontal direction.
These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children (using Flexible rather than Expanded). This will allow the flexible children to size themselves to less than the infinite remaining space they would otherwise be forced to take, and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.

Some problems with all the durations

I don't know exactly what's going on, but setting these durations is near impossible to get right.

Most of the time the tooltip doesn't show up. It must be hiding the tooltip in timers that get fired at the wrong time.

Very confusing to set this up.

Add goldens to pubignore

Those images are quite large and to force every user to install them with a standard install is wack

Barrier should not be visually on top of child widget

A custom user built barrier shouldn't visually obscure the child widget. This doesn't really match with what a user would expect and naturally bars a lot of users from using the tooltip as a sort of coach or app guide such as the following:

A couple of possibilities to get what we want would be to:

  1. shadermasks (credit caseycrogers)
  2. a duplicate overlay entry of the child
  3. a clip mask or user defined clip mask

or something else

coachmaker does something similar so it might help to get inspiration from them.

Making a button to show a tooltip when it's a non-modal closes the modal immediately

This is semi expected behavior as the tooltip adds a global listener for taps and will close the tooltip if there's any taps. However, I don't think it should happen the second the tooltip is created.

The tap handler should should ignore all taps until hasEntry is true

Edit

It does wait until it has an entry. It still doesn't handle it correctly

void _handlePointerEvent(PointerEvent event) {
    if (!delegate.hasEntry) return;

    if (event is PointerUpEvent || event is PointerCancelEvent) {
      _hideTooltip();
    } else if (event is PointerDownEvent) {
      _hideTooltip(immediately: true);
    }
  }

onShow, onHide callbacks

I am using a widget by tapping it i am showing a tooltip. but i also want to change the size, colour of the tooltip but unable to do because i am not getting any callback of show and close in which i can change the widget.It would be great if those call backs are added soon. Thank you.

isModal:true makes the tooltip persistant (on previous page) when a GestureDetector of higher level pushes the navigator to a new route...

...Not allowing the tooltip to show for any new item on the new route (as the previous one wasn't closed 'properly'. It also doesn't allow it to close on the new page as it technically doesn't exist on that page? Lets look at this example:

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Error App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Error'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

  const MyHomePage({
    Key? key,
    required this.title,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center: (child: GestureDetector(
        onDoubleTap: () {
          Navigator.push<void>(
            context,
            MaterialPageRoute(builder: (context) {
              FocusScope.of(context).unfocus();
              return SecondPage();
            }),
          );
        },
        child: ToolTipBug(
          description: 'Hello',
        ),
      ),
     ),
   );
  }
}

class ToolTipBug extends StatelessWidget {
  final String description;

  const ToolTipBug({
    Key? key,
    required this.description,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return JustTheTooltip(
      isModal: true,
      triggerMode: TooltipTriggerMode.tap,
      content: Text(description),
      child: SizedBox(
        height: 100,
        child: Center(child: Text('Test')),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  const SecondPage({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {


    return  Scaffold(
      appBar: AppBar(
        title: Text('Page 2'),
      ),
      body: Center: (
        child: ToolTipBug(
          description: 'hello 2',
        ),
      ),
   );
  }
}


Lets consider this simple example. When you open the tooltip and then double click on the MyHomePage Class, and you go to the SecondPage, you expect the modal of the previous page to be closed and that you will be able to open the second ToolTipBug Widget on SecondPage by cliking on it but this doesn't happen. The previous modal in the MyHomePage Class persists (but is not there) and nothing opens in the new page. This behaviour only happens when isModal is set to true.

Prevent the tooltip from closing on clicking on it

Is this how it was intended, that the tooltip closes when you click on it?

Can this be disabled somehow?

I think such property values (that I have set) should prevent this.

triggerMode: TooltipTriggerMode.manual,
barrierDismissible: false,

But it doesn't work that way.

Error when using inside a ListView

I noticed a problem in the use of this library when used with the area mode and the tooltip inside a ListView or a GridView on Flutter 2.10.1.

When the widget that contains the tooltip is activated and move to outside of ListView, its cause this error

FlutterError (setState() or markNeedsBuild() called during build.
This ValueListenableBuilder<Widget?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.

Possible to reproduce on example:
https://github.com/Nolence/just_the_tooltip/blob/main/example/lib/pages/tooltip_area_page.dart

Differentiate between `immediately` and `withoutAnimation`

I just got really confused by thinking immediately referred to an action the tooltip took without animation. That is not the case. immediately in the original Tooltips case implies that they're not waiting for hover hide/show duration.

That's cool and all, but for a controller, we'll want to be able to specify immediately in terms of, skip the whole animation thing. We also don't need to worry about that stuff in terms of modals as they're driven by taps

Make tests less bad

I'm currently doing the most naive golden tests. I couldn't find out a way to use to use a screenbuilder with various screens without breaking the tooltip. It wouldn't break but because internally the golden test lib is just resizing things instead of relaying them out as well, the tooltip was being pushed to the edge.

I'd like scenerios like the following example from flutter_glove_box:

final builder = DeviceBuilder()
      ..overrideDevicesForAllScenarios(devices: [
        Device.phone,
        Device.iphone11,
        Device.tabletPortrait,
        Device.tabletLandscape,
      ])
      ..addScenario(
        widget: FlutterDemoPage(),
        name: 'default page',
      )
      ..addScenario(
        widget: FlutterDemoPage(),
        name: 'tap once',
        onCreate: (scenarioWidgetKey) async {
          final finder = find.descendant(
            of: find.byKey(scenarioWidgetKey),
            matching: find.byIcon(Icons.add),
          );
          expect(finder, findsOneWidget);
          await tester.tap(finder);
        },
      )
      ..addScenario(
        widget: FlutterDemoPage(),
        name: 'tap five times',
        onCreate: (scenarioWidgetKey) async {
          final finder = find.descendant(
            of: find.byKey(scenarioWidgetKey),
            matching: find.byIcon(Icons.add),
          );
          expect(finder, findsOneWidget);

          await tester.tap(finder);
          await tester.tap(finder);
          await tester.tap(finder);
          await tester.tap(finder);
          await tester.tap(finder);
        },
      );

but where I can choose to do something in between different devices. Like a hook before the screenshot is taken.

LateInitializationError: Field '_controller@1501137672' has already beenย  initialized

Hi, I have error when I try create a new justTheController
Any ideas?

StackTrace: #0ย  ย  ย  LateError._
throwFieldAlreadyInitialized (dart:_internal-patch\/internal_patch.dart:211)\n#1ย  ย  ย  _JustTheToolt
ipState._controller= (package:just_the_tooltip\/src\/just_the_tooltip.dart:150)\n#2ย  ย  ย  _JustTheTo
oltipState.didUpdateWidget (package:just_the_tooltip\/src\/just_the_tooltip.dart:222)\n#3ย  ย  ย  Stat
efulElement.update (package:flutter\/src\/widgets\/framework.dart:4855)\n#4ย  ย  ย  Element.updateChil
d (package:flutter\/src\/widgets\/framework.dart:3412)\n#5ย  ย  ย  ComponentElement.performRebuild (pa
ckage:flutter\/src\/widgets\/framework.dart:4690)\n#6ย  ย  ย  Element.rebuild (package:flutter\/src\/w
idgets\/framework.dart:4355)\n#7ย  ย  ย  StatelessElement.update (package:flutter\/src\/widgets\/frame
work.dart:4746)\n#8ย  ย  ย  Element.updateChild (package:flutter\/src\/widgets\/framework.dart:3412)\n
#9ย  ย  ย  ComponentElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4690)\n#10
ย ย  StatefulElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4840)\n#11 ย  ย  Ele
ment.rebuild (package:flutter\/src\/widgets\/framework.dart:4355)\n#12 ย  ย  StatefulElement.update (
package:flutter\/src\/widgets\/framework.dart:4872)\n#13 ย  ย  Element.updateChild (package:flutter\/
src\/widgets\/framework.dart:3412)\n#14 ย  ย  Element.inflateWidget (package:flutter\/src\/widgets\/f
ramework.dart:3663)\n#15 ย  ย  Element.updateChild (package:flutter\/src\/widgets\/framework.dart:342
5)\n#16 ย  ย  ComponentElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4690)\n#
17 ย  ย  StatefulElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4840)\n#18
ย Element.rebuild (package:flutter\/src\/widgets\/framework.dart:4355)\n#19 ย  ย  ComponentElement._fi
rstBuild (package:flutter\/src\/widgets\/framework.dart:4643)\n#20 ย  ย  StatefulElement._firstBuild
(package:flutter\/src\/widgets\/framework.dart:4831)\n#21 ย  ย  ComponentElement.mount (package:flutt
er\/src\/widgets\/framework.dart:4638)\n#22 ย  ย  Element.inflateWidget (package:flutter\/src\/widget
s\/framework.dart:3673)\n#23 ย  ย  Element.updateChild (package:flutter\/src\/widgets\/framework.dart
:3425)\n#24 ย  ย  ComponentElement.performRebuild (package:flutter\/src\/widgets\/framework.dart:4690
...
#201ย  ย  BuildOwner.buildScope (package:flutter\/src\/widgets\/framework.dart:2620)\n#202ย  ย  Widgets
Binding.drawFrame (package:flutter\/src\/widgets\/binding.dart:882)\n#203ย  ย  RendererBinding._handl
ePersistentFrameCallback (package:flutter\/src\/rendering\/binding.dart:319)\n#204ย  ย  SchedulerBind
ing._invokeFrameCallback (package:flutter\/src\/scheduler\/binding.dart:1143)\n#205ย  ย  SchedulerBin
ding.handleDrawFrame (package:flutter\/src\/scheduler\/binding.dart:1080)\n#206ย  ย  SchedulerBinding
._handleDrawFrame (package:flutter\/src\/scheduler\/binding.dart:996)\n#207ย  ย  _rootRun (dart:async
\/zone.dart:1428)\n#208ย  ย  _CustomZone.run (dart:async\/zone.dart:1328)\n#209ย  ย  _CustomZone.runGua
rded (dart:async\/zone.dart:1236)\n#210ย  ย  _invoke (dart:ui\/hooks.dart:166)\n#211ย  ย  PlatformDispa
tcher._drawFrame (dart:ui\/platform_dispatcher.dart:270)\n#212ย  ย  _drawFrame (dart:ui\/hooks.dart:1
29)\n \n\n Error message: LateInitializationError: Field '_controller@1501137672' has already beenย 
initialized

Customizability of tooltip

We should allow for more customizations. A good starting point would be to try to implement some of these:

  • Frosted look
  • Outline of tooltip
  • Better Shadow properties (List?)

Edit

I might want to consider whether the tooltip should be the space around the tail as well and if the tail should just be gotten from a clipper. That would make things like frosted glass a lot easier to implement. I think it'd complicate gestures though. Just a guess.

Show the tooltip programatically

Forcing the child onTap to show the tooltip is not cool. It might be the default behavior but we should be able to decide when we want to show the tooltip in the app. Think of onboarding scenarios.

Back button not called when tooltip visible

I think this occurs when you use the default AppBar(). This creates a back button that has a maybePop() call when a back it triggered. The maybePop likely sees the overlays and sends a false back.

One workaround I've found is to replace the skrim's default gestureDetector

Widget _createSkrim() {
  return GestureDetector(
    key: skrimKey,
    behavior: HitTestBehavior.translucent,
    onTap: _hideTooltip,
  );
}

with a

Widget _createSkrim() {
  return Listener(
    key: skrimKey,
    behavior: HitTestBehavior.translucent,
    onPointerDown: (_) => _hideTooltip(),
  );
}

But this creates the weird case where when you're dragging, the tooltip is immediately closed because an onPointerDown event was sent.

Listener
https://user-images.githubusercontent.com/29642168/135305144-46ed33e3-49ee-4659-98ac-2f2a879283e0.mp4

GestureDetector
https://user-images.githubusercontent.com/29642168/135305163-17499af7-85cc-4c98-8dac-2e8193eb50bf.mp4

JustTheController doesn't reflect the correct tooltip status

It's easy to reproduce, just add a listener to the JustTheController instance. And check 'isShowing' within the closure, like what I did in the PR.

As I mentioned in the PR, JustTheController as a ValueNotifier, ideally, it should reflect the current status of tooltip, like open or close. I noticed you have implemented these functions: 'isShowing' and 'isHidden', however, it's broken, the value never changes.

I also tried to fix it directly, but the value will be changed multiple times during each user action, that means, if I listen to JustTheController, the listener will be invoked multiple times for each user action. Potentially, this listener behavior would cause some unnecessary issues. That's why I end up with creating a new status notifier. Maybe you have better implementation. Please let me know if you have any questions.

After a hot reload, RenderObject does not relayout

This means if we change the axis, no new constraints are processed.

This likely will be fixed with making each property a setter and getter and making the correct thing dirty. Either paint or layout.

Look at simple_tooltip

Dear diary, just saw this other package and its whack how much we have alike. Unlike their package, I use a custom render object instead of drawing a frame late. They somehow manage update the tooltip in realtime as the target moves though which is cool. I think I'll see if I can't get some pointers from them.

Use RenderProxyBox for child position and size

Although I do think what I'm currently doing is a little bit hacky, considering I have 10+ fields on the widget state, I'd need to create those same fields on the CustomRenderObject and update them all accordingly. This is super verbose.

My current workaround is just to get the RenderBox of child's self at runtime when it's requested to show a tooltip.

TargetInformation _getTargetInformation(BuildContext context) {
  final box = context.findRenderObject() as RenderBox?;

  if (box == null) {
    throw StateError(
      'Cannot find the box for the given object with context $context',
    );
  }

  final targetSize = box.getDryLayout(const BoxConstraints.tightForFinite());
  final target = box.localToGlobal(box.size.center(Offset.zero));
  final offsetToTarget = Offset(
    -target.dx + box.size.width / 2,
    -target.dy + box.size.height / 2,
  );

  return TargetInformation(
    targetSize,
    target,
    offsetToTarget,
  );
}

Add Notifications for tooltip events

I imagine this would be useful to see when a tooltip is on the screen and where. Top level UI might find something to do with this information.

I saw a neat answer from Remi on Notifications. This is a separate from a controller.

https://stackoverflow.com/a/51460832/8213910

We would add notifaction listener and possibly provide:

  • target postion and sizing
  • tooltip direction and sizing
  • visible, hidden
  • more possibly

provide Alignment argument

Let's add an Alignment argument that the tooltip center will use to position itself. For example, we could provide a value of Alignment.topRight and the tail tip will point itself on the child's box at the topRight corner. We'd likely need to flip the Alignment (multiply by -1) if we end up positioning ourselves in the opposite of preferredAxis.

Scroll constraints should not allot full scroll extent if size does not require it

I currently allow stuff that pass me a scroll controller to go past the immediate viewport into extentBefore and extentAfter. HOWEVER. If it's something that chooses to expand as large as possible such as a Center then we should try constraining the child size first to the viewport and then, if it fails, fallback to giving it all the possible size.

Ability to place tail tip along cross axis

For vertical text boxes like japanese, it'd be cool if you could center the tip along the center vertical axis.

Simulator Screen Shot - iPod touch (7th generation) - 2021-06-17 at 11 25 19

This would involve doing some black magic on cross axis code of vertical|horizontal PositionDependentBox function. Namely, we'd likely pass through an alignment and do it based off that. The code below favors the left margin I think

// HORIZONTAL DIRECTION
  double x;
  if (size.width - margin.horizontal < childSize.width) {
    x = (size.width - childSize.width) / 2.0;
  } else {
    final normalizedTargetX =
        target.dx.clamp(margin.left, size.width - margin.right);
    final edge = margin.left + childSize.width / 2.0;
    if (normalizedTargetX < edge) {
      x = margin.left;
    } else if (normalizedTargetX > size.width - edge) {
      x = size.width - margin.left - childSize.width;
    } else {
      x = normalizedTargetX - childSize.width / 2.0;
    }
  }

Center and Circular progress indicator

This ends up taking the whole height instead of the minimum !

Agh, it probably has to do with intrinsics again....

The expected behaviour is that it takes the minimum amount of height for just the circularprogressindicator

Simulator Screen Shot - iPod touch (7th generation) - 2021-07-01 at 14 21 38

How to add Hover

When I hover the button this tooltip need to show how to do this

Error: Type 'TooltipTriggerMode' not found. final TooltipTriggerMode? triggerMode

app is working in debug mode, but its throwing several errors when i try to build the APK. Bellow i will mention the errors which i got.

`../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:80:9: Error: Type 'TooltipTriggerMode' not found.
final TooltipTriggerMode? triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:288:16: Error: Type 'TooltipTriggerMode' not found.
static const TooltipTriggerMode _defaultTriggerMode =
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:300:8: Error: Type 'TooltipTriggerMode' not found.
late TooltipTriggerMode triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip_entry.dart:60:9: Error: Type 'TooltipTriggerMode' not found.
final TooltipTriggerMode? triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/models/just_the_interface.dart:125:3: Error: Type 'TooltipTriggerMode' not found.
TooltipTriggerMode? get triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:289:7: Error: Getter not found: 'TooltipTriggerMode'.
TooltipTriggerMode.longPress;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:80:9: Error: 'TooltipTriggerMode' isn't a type.
final TooltipTriggerMode? triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:288:16: Error: 'TooltipTriggerMode' isn't a type.
static const TooltipTriggerMode _defaultTriggerMode =
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:300:8: Error: 'TooltipTriggerMode' isn't a type.
late TooltipTriggerMode triggerMode;
^^^^^^^^^^^^^^^^^^
../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:559:26: Error: The getter 'TooltipTriggerMode' isn't defined for the class '_JustTheTooltipState'.

  • '_JustTheTooltipState' is from 'package:just_the_tooltip/src/just_the_tooltip.dart' ('../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'TooltipTriggerMode'.
    if (triggerMode == TooltipTriggerMode.longPress) {
    ^^^^^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:581:44: Error: The getter 'triggerMode' isn't defined for the class 'TooltipThemeData'.
  • 'TooltipThemeData' is from 'package:flutter/src/material/tooltip_theme.dart' ('../../src/flutter_2.2.3/packages/flutter/lib/src/material/tooltip_theme.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'triggerMode'.
    widget.triggerMode ?? tooltipTheme.triggerMode ?? _defaultTriggerMode;
    ^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:583:22: Error: The getter 'enableFeedback' isn't defined for the class 'TooltipThemeData'.
  • 'TooltipThemeData' is from 'package:flutter/src/material/tooltip_theme.dart' ('../../src/flutter_2.2.3/packages/flutter/lib/src/material/tooltip_theme.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'enableFeedback'.
    tooltipTheme.enableFeedback ??
    ^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:590:29: Error: The getter 'TooltipTriggerMode' isn't defined for the class '_JustTheTooltipState'.
  • '_JustTheTooltipState' is from 'package:just_the_tooltip/src/just_the_tooltip.dart' ('../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'TooltipTriggerMode'.
    : (triggerMode == TooltipTriggerMode.longPress)
    ^^^^^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart:595:29: Error: The getter 'TooltipTriggerMode' isn't defined for the class '_JustTheTooltipState'.
  • '_JustTheTooltipState' is from 'package:just_the_tooltip/src/just_the_tooltip.dart' ('../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named 'TooltipTriggerMode'.
    : (triggerMode == TooltipTriggerMode.tap)
    ^^^^^^^^^^^^^^^^^^
    ../../src/flutter_2.2.3/.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.10/lib/src/just_the_tooltip_entry.dart:60:9: Error: 'TooltipTriggerMode' isn't a type.
    final TooltipTriggerMode? triggerMode;
    ^^^^^^^^^^^^^^^^^^

FAILURE: Build failed with an exception.

  • Where:
    Script '/home/mindstack/src/flutter_2.2.3/packages/flutter_tools/gradle/flutter.gradle' line: 1035

  • What went wrong:
    Execution failed for task ':app:compileFlutterBuildRelease'.

Process 'command '/home/mindstack/src/flutter_2.2.3/bin/flutter'' finished with non-zero exit value 1

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

  • Get more help at https://help.gradle.org
    `

Tooltip does not work with TextField

โ•โ•โ•โ•โ•โ•โ•โ• Exception caught by rendering library โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following assertion was thrown during performLayout():
The _RenderDecoration class does not support dry layout.

Layout requires baseline metrics, which are only available after a full layout.
The relevant error-causing widget was
TooltipOverlay
../โ€ฆ/src/just_the_tooltip.dart:227
When the exception was thrown, this was the stack
#0      RenderBox.debugCannotComputeDryLayout.<anonymous closure>
package:flutter/โ€ฆ/rendering/box.dart:1901
#1      RenderBox.debugCannotComputeDryLayout
package:flutter/โ€ฆ/rendering/box.dart:1911
#2      _RenderDecoration.computeDryLayout
package:flutter/โ€ฆ/material/input_decorator.dart:1300
#3      RenderBox._computeDryLayout
package:flutter/โ€ฆ/rendering/box.dart:1824
#4      RenderBox.getDryLayout.<anonymous closure>
package:flutter/โ€ฆ/rendering/box.dart:1813
#5      _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:311:23)
#6      RenderBox.getDryLayout
package:flutter/โ€ฆ/rendering/box.dart:1813
#7      RenderProxyBoxMixin.computeDryLayout
package:flutter/โ€ฆ/rendering/proxy_box.dart:108
#8      RenderBox._computeDryLayout
package:flutter/โ€ฆ/rendering/box.dart:1824
#9      RenderBox.getDryLayout.<anonymous closure>
package:flutter/โ€ฆ/rendering/box.dart:1813

This is probably because I'm calling getDryLayout on the child and it doesn't have that available for textfields. I think there's a debug version available that knows though isn't there?

Vertical space filling tooltip overflowed

I don't think this should overflow as I've passed in a scroll Controller and there is technically space both before and after. If anything, this looks weird in where it decides to stop drawing. Are those the constaints?

Simulator Screen Shot - iPod touch (7th generation) - 2021-06-28 at 09 36 32

class TooltipAreaExamplePage extends StatefulWidget {
  const TooltipAreaExamplePage({Key? key}) : super(key: key);

  @override
  State<TooltipAreaExamplePage> createState() => _TooltipAreaExamplePageState();
}

class _TooltipAreaExamplePageState extends State<TooltipAreaExamplePage> {
  final titleController = TextEditingController(
    text: 'Lorem ipsum dolor',
  );
  final descriptionController = TextEditingController(
    text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do '
        'eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim '
        'ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut ',
  );
  final scrollController = ScrollController();

  @override
  void dispose() {
    titleController.dispose();
    descriptionController.dispose();
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('It goes under me')),
      body: JustTheTooltipArea(
        builder: (context, tooltip, scrim) {
          return Stack(
            fit: StackFit.passthrough,
            children: [
              ListView(
                controller: scrollController,
                children: List.generate(
                  40,
                  (index) {
                    if (index == 15) {
                      return JustTheTooltipEntry(
                        scrollController: scrollController,
                        isModal: true,
                        tailLength: 20.0,
                        preferredDirection: AxisDirection.right,
                        margin: const EdgeInsets.all(16.0),
                        child: const Material(
                          color: Colors.blue,
                          shape: CircleBorder(),
                          elevation: 4.0,
                          child: Padding(
                            padding: EdgeInsets.all(8.0),
                            child: Icon(
                              Icons.touch_app,
                              color: Colors.white,
                            ),
                          ),
                        ),
                        content: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            TextField(
                              maxLines: null,
                              keyboardType: TextInputType.text,
                              textCapitalization: TextCapitalization.sentences,
                              style: Theme.of(context).textTheme.headline6,
                              controller: titleController,
                            ),
                            const SizedBox(height: 12.0),
                            TextField(
                              controller: descriptionController,
                              maxLines: null,
                              keyboardType: TextInputType.multiline,
                              textCapitalization: TextCapitalization.sentences,
                              style: Theme.of(context).textTheme.subtitle1,
                            ),
                            const SizedBox(height: 16.0),
                            Row(
                              mainAxisAlignment: MainAxisAlignment.spaceAround,
                              children: [
                                Expanded(
                                  child: OutlinedButton(
                                    style: OutlinedButton.styleFrom(
                                      shape: const StadiumBorder(),
                                    ),
                                    onPressed: () {},
                                    child: const Text('exercises'),
                                  ),
                                ),
                                const SizedBox(width: 16.0),
                                Expanded(
                                  child: OutlinedButton(
                                    style: OutlinedButton.styleFrom(
                                      shape: const StadiumBorder(),
                                    ),
                                    onPressed: () {},
                                    child: const Text('course'),
                                  ),
                                ),
                              ],
                            )
                          ],
                        ),
                      );
                    }

                    return ListTile(title: Text('Item $index'));
                  },
                ),
              ),
              if (scrim != null) scrim,
              if (tooltip != null) tooltip,
            ],
          );
        },
      ),
    );
  }
}

tooltip in ListView item crash

I haven't investigated this yet. But I added a tooltip on some listview items and I'm getting this:

[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: RenderFlex children have non-zero flex but incoming width constraints are unbounded.
When a row is in a parent that does not provide a finite width constraint, for example if it is in a horizontal scrollable, it will try to shrink-wrap its children along the horizontal axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the horizontal direction.
These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children (using Flexible rather than Expanded). This will allow the flexible children to size themselves to less than the infinite remaining space they would otherwise be forced to take, and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.
If this message did not help you determine the problem, consider using debugDumpRenderTree():
https://flutter.dev/debugging/#rendering-layer
http://api.flutter.dev/flutter/rendering/debugDumpRenderTree.html
The affected RenderFlex is:
RenderFlex#88256 relayoutBoundary=up18(creator: Row โ† Padding โ† DefaultTextStyle โ† Builder โ† Semantics โ† DefaultTextStyle โ† AnimatedDefaultTextStyle โ† _InkFeatures-[GlobalKey#2bfc5 ink renderer] โ† NotificationListener โ† CustomPaint โ† _ShapeBorderPaint โ† PhysicalShape โ† โ‹ฏ, parentData: offset=Offset(10.0, 10.0) (can use size), constraints: BoxConstraints(w=849.8, 0.0<=h<=Infinity), size: Size(849.8, 60.0), direction: horizontal, mainAxisAlignment: start, mainAxisSize: max, crossAxisAlignment: center, textDirection: ltr, verticalDirection: down)
The creator information is set to:
Row โ† Padding โ† DefaultTextStyle โ† Builder โ† Semantics โ† DefaultTextStyle โ† AnimatedDefaultTextStyle โ† _InkFeatures-[GlobalKey#2bfc5 ink renderer] โ† NotificationListener โ† CustomPaint โ† _ShapeBorderPaint โ† PhysicalShape โ† โ‹ฏ
See also: https://flutter.dev/layout/
If none of the above helps enough to fix this problem, please don't hesitate to file a bug:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
#0 RenderBox.debugCannotComputeDryLayout.
#1 RenderBox.debugCannotComputeDryLayout
#2 RenderFlex.computeDryLayout
#3 RenderBox._computeDryLayout
#4 RenderBox.getDryLayout.
#5 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#6 RenderBox.getDryLayout
#7 RenderPadding.computeDryLayout
#8 RenderBox._computeDryLayout
#9 RenderBox.getDryLayout.
#10 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#11 RenderBox.getDryLayout
#12 RenderProxyBoxMixin.computeDryLayout
#13 RenderBox._computeDryLayout
#14 RenderBox.getDryLayout.
#15 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#16 RenderBox.getDryLayout
#17 RenderProxyBoxMixin.computeDryLayout
#18 RenderBox._computeDryLayout
#19 RenderBox.getDryLayout.
#20 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#21 RenderBox.getDryLayout
#22 RenderProxyBoxMixin.computeDryLayout
#23 RenderBox._computeDryLayout
#24 RenderBox.getDryLayout.
#25 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#26 RenderBox.getDryLayout
#27 RenderProxyBoxMixin.computeDryLayout
#28 RenderBox._computeDryLayout
#29 RenderBox.getDryLayout.
#30 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#31 RenderBox.getDryLayout
#32 RenderPadding.computeDryLayout
#33 RenderBox._computeDryLayout
#34 RenderBox.getDryLayout.
#35 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#36 RenderBox.getDryLayout
#37 RenderProxyBoxMixin.computeDryLayout
#38 RenderBox._computeDryLayout
#39 RenderBox.getDryLayout.
#40 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#41 RenderBox.getDryLayout
#42 RenderProxyBoxMixin.computeDryLayout
#43 RenderBox._computeDryLayout
#44 RenderBox.getDryLayout.
#45 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#46 RenderBox.getDryLayout
#47 RenderProxyBoxMixin.computeDryLayout
#48 RenderBox._computeDryLayout
#49 RenderBox.getDryLayout.
#50 _LinkedHashMapMixin.putIfAbsent (dart:collection-patch/compact_hash.dart:314:23)
#51 RenderBox.getDryLayout
#52 _JustTheTooltipState._getTargetInformation
#53 _JustTheTooltipState._createEntry
#54 _JustTheTooltipState._createNewEntries
#55 _JustTheTooltipState.ensureTooltipVisible
#56 _JustTheTooltipState._showTooltip.
#57 _JustTheTooltipState._showTooltip.
#58 _rootRun (dart:async/zone.dart:1420:47)
#59 _CustomZone.run (dart:async/zone.dart:1328:19)
#60 _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#61 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1276:23)
#62 _rootRun (dart:async/zone.dart:1428:13)
#63 _CustomZone.run (dart:async/zone.dart:1328:19)
#64 _CustomZone.bindCallback. (dart:async/zone.dart:1260:23)
#65 Timer._createTimer. (dart:async-patch/timer_patch.dart:18:15)
#66 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395:19)
#67 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426:5)
#68 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:187:12)

Get rid of JustTheInterface

I think I previously was using it to avoid passing through super parameters but with new super language feature in dart it's relatively easy. It would also just be nice because this is very non-standard the way I do it.

Null safety issue

I'm getting this error while building my app:


ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:329:27: Warning: Operand of null-aware operation '!' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:           RendererBinding.instance!.mouseTracker.mouseIsConnected;
ERROR:                           ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:393:21: Warning: Operand of null-aware operation '!' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:     RendererBinding.instance!.mouseTracker
ERROR:                     ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:397:20: Warning: Operand of null-aware operation '!' has type 'GestureBinding' which excludes null.
ERROR:  - 'GestureBinding' is from 'package:flutter/src/gestures/binding.dart' ('/opt/flutter/packages/flutter/lib/src/gestures/binding.dart').
ERROR:     GestureBinding.instance!.pointerRouter.addGlobalRoute(_handlePointerEvent);
ERROR:                    ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:402:21: Warning: Operand of null-aware operation '?.' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:     RendererBinding.instance?.mouseTracker
ERROR:                     ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:404:20: Warning: Operand of null-aware operation '?.' has type 'GestureBinding' which excludes null.
ERROR:  - 'GestureBinding' is from 'package:flutter/src/gestures/binding.dart' ('/opt/flutter/packages/flutter/lib/src/gestures/binding.dart').
ERROR:     GestureBinding.instance?.pointerRouter
ERROR:                    ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:414:25: Warning: Operand of null-aware operation '!' has type 'RendererBinding' which excludes null.
ERROR:  - 'RendererBinding' is from 'package:flutter/src/rendering/binding.dart' ('/opt/flutter/packages/flutter/lib/src/rendering/binding.dart').
ERROR:         RendererBinding.instance!.mouseTracker.mouseIsConnected;
ERROR:                         ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip.dart:498:22: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
ERROR:  - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('/opt/flutter/packages/flutter/lib/src/widgets/binding.dart').
ERROR:       WidgetsBinding.instance?.addPostFrameCallback((_) async {
ERROR:                      ^
ERROR: ../../.pub-cache/hosted/pub.dartlang.org/just_the_tooltip-0.0.11+2/lib/src/just_the_tooltip_entry.dart:210:20: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
ERROR:  - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('/opt/flutter/packages/flutter/lib/src/widgets/binding.dart').
ERROR:     WidgetsBinding.instance?.addPostFrameCallback((_) {
ERROR:                    ^

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.