text:
Opt a subtree out of hitTestSelf culling

We often get questions about why hit testing "doesn't work" around transforms. The short answer is that ancestors don't ask their children to hit test if their own hitTestSelf fails (no point asking your children if they were hit if the hit wasn't inside your bounds).
@csells suggested that it would be nice if a subtree could opt-in to not doing that culling. Obviously that would in general be expensive but it would be less expensive than doing a full tree walk (unless someone opted out the entire tree, obviously). I think we would still avoid doing this ever in the Flutter framework since it's better to adjust the widget hierarchy to not have ancestors of the transformed widget be smaller than that widget, but it might be useful in especially elaborate scenes where that is impractical.
One way to do that would be to have HitTestResult have a flag that says whether to apply the hitTestSelf check. Having to check that flag every step of the walk would itself be not cheap, but the cost (which affects every app) might still be worth it?
Another option might be to have a way for a widget to hook into the hit testing of a far ancestor (e.g. via an inherited widget). That would be better in that it would allow the whole thing to be done as a package. Maintaining paint order correctness would be distinctly non-trivial though (maybe even intractable).
Any other ideas?
cc @goderbauer

A solution for this would also help with the often raised complained that you can't hit-test children drawn in the visual overflow of a stack (see discussion at https://github.com/flutter/flutter/issues/19445).

it would be nice if a subtree could opt-in to not doing that culling. Obviously that would in general be expensive but it would be less expensive than doing a full tree walk (unless someone opted out the entire tree, obviously).

I believe choosing the root of the subtree that you want to opt out will not not be easy. The root will not be the transform widget that moves a child out of its bounds. It has to be an ancestor, who has the transformed descendant still in its bounds. Otherwise, the hit test would never reach the transform widget or the transformed child. I am wondering, if in practice that would encourage people to basically opt-out the entire tree...

Would be interesting to study a use case, that we would enable (or make significantly simpler over e.g. re-organizing the widget tree) by having this mechanism. Do we have one?

I can certainly provide a number of use cases, just slammed right now. I'll circle back in a cpl weeks when things calm down a bit.
Generally speaking, it's any time you want to de-couple things, and have some child with children of it's own, that want to hang off the side of that parent.  Think a classic web-menu with pop-out panels that overhang outside a column/row, or an expanding search bar that starts in a column, but then expands downward, or even a panel with a scrollbar, where the scrollbar sits in negative padding. All of these things want to start inside the box-layout of Flutter (column/row/positioned) but then easily expand outside it.
If you can't just offset a child outside yourself, the alternative, usually involves putting the 2 siblings in a stack. In practice, this is not too bad if you plan from the start for it, but it's really limiting when requirements change, and you have some existing widget tree, that is not lending itself easily to changing form.
As a simple example, lets say I have a system for sizing content in a stack, and it looks like this:

Immediately we run into this issue. The most maintainable and portable way to build it as an end user of Flutter is:

Define the content box, in a Stack, at it's true height 300x100
From within the box, decorate itself by offseting the drag handles slightly into negative space
Moving the "300x100" into negative space, relative to our center (lets assume this thing needs to be clickable as well).

What we want to write is something really simple like this, where all the sizing info is self-contained within the Box widget:
Stack(
children: [
    MyBoxContent(),
    // Corners can sit in negative space, very easy to change size of these btns later.
   // All the sizing logic is here, relative to this box. No co-ordination with parent needed.
    Positoned(
      top: -btnSize/2,  left: -btnSize/2, right: -btnSize/2, bottom: -btnSize/2,
      child: SelectionHandles()
    ),
    /// Bottom SizePanel
    Align(
        alignment: Alignment.bottomCenter,
        child: FractionalTranslation(
            offset: Offset(0, -1),
            child: SizePanel()))
  ]
)

The parent does need to be concerned with what we're doing in our negative margins, it just sizes the box. The box is free to decorate itself with any "hanging widgets" it needs, without fighting the frameworks hit-detection algorithm.
This creates a super portable 'thing' there is no impact to the Widget tree around, and its super portable. From outside, the code is easily read. So you can imagine how useful this can be when you get some last-minute design request to move some thing slightly outside it's parent bounds...
If we can't just use the offset trick, we would actually need to make the size of our box something like:
// Each box needs this sizing info, from the parent, who really shouldn't care about this cludge...
width: 300 + btnSize/2,
// Add more extra height into the box, just to support hit detection, that the box will need to remove later
height: 300 + btnSize/2 + Insets.paddingLarge + SizePanel.kHeight,

And inside the box, we need to size our content in some hack way like:
content.width = widget.width - CornersBtns.kBtnSize; // 2 halfs combined, is the 'extra' space passed in from parent
content.height = widget.height -  SizePanel.height; // We need to just know that our parent has passed us this extra space

These two layers need to coordinate somehow, either by passing down but sizing info, or defining a bunch of constants.
This code is extremely representative of what gets written when we are trying to work around these sorts of issues, where anytime something wants to "go outside the box", our only answer is "add more box".

The usual solution to that problem is the Overlay. See e.g. how the text editing toolbar is done.

Ya, I think that's kinda the problem this would address. It would give us some middle ground. It also shows the problem with giving examples, because the response will tend to be "Use overlay".
Overlay is quite complicated to learn, and verbose to use. Kinda feels like a sledgehammer when what you more-often need is a chisel? Especially once you add the LayerLink and CompositeTransformFollower into the mix, vs this, which is like 20 characters and a smidge of negative padding and gets all of the following behavior for free.
Many devs have no clue how to use Overlay, and be immediately scared off of the code. While everyone is familiar with the concept of negative margin, and virtually no one expects btns to stop working when in negative space.
Yes we have to manage sorting, but that's expected from other stacks that work this way (dom, unity, flash), so it's a universal thing almost every developer is somewhat familiar with. Flutter is well-suited to tweaking render order anyways, it can do just-in-time imperative re-orders with dart, or flow the Flexible up/down, so it's never much of a problem to put something "on top", it's actually much easier here to control our render order than any of those other stacks because it's all dart code and List<>'s.
Like if you look at it from the perspective of the developer writing code. There is absolutely no attraction to using a more complex approach if the simple one will do. We just want the most options possible, and will always favor the simplest most maintainable KISS approach. If we do have a single thing, that needs a full-screen Modal, we can opt for Overlay. If we have a bunch of multi-select boxes, or some btns we just want to nudge over -10px to line-up visually, Overlay is not particularly well suited.
A simple Widget that just says "Anything in this sub-tree is clickable, if it's visible" would be a great tool in the toolbox.

Having been on the CSS working group in an earlier life, I have to say I get much much more scared by negative margins than anything like the Overlay. :-)
Anyway I'm not saying Overlay is the answer; if I was, I wouldn't have filed this bug. I'm just saying that that's the way to do it today.

No worries I get it. Everything is double-edged. Flutter is such an expressive framework though, I always feel it's a shame to be locked too rigidly inside the box (well we're not actually, just our hits are :'( )
By way of example, here is a specific use case I don't think overlay actually supports (negative margins wouldn't either fwiw):
https://user-images.githubusercontent.com/736973/108322563-d6e5be80-7182-11eb-9616-ee4b40db941d.mp4
Here we want the overlay always to have 1px outline, but to otherwise follow the "size" of of the follow-target.
With overlay, using CompositeTransformFollower, the overlay is actually transformed rather than sized to match. In this example the red-box is an OverlayEntry, If using Overlay for the use case above, I would want "Hello" to maintain it's size, and the margins around it change, but instead the whole thing is zoomed. In this case we are just parented inside a InteractiveViewer.
https://user-images.githubusercontent.com/736973/108323434-e7e2ff80-7183-11eb-9174-ddd962483279.mp4
This isn't really related to this issue, but a good use case where Overlay should be the perfect solution, but doesn't quite work as needed, but that small gap makes it basically unusable for the use-case.

A nice thing about having this Widget is that it will let us put some sort of number to this. Curious if we're talking 10ms, 1ms or .1ms when we say it's an expensive thing to apply to the tree.

As an example of why Overlay is just hard to deal with, I had an idea: "What if I can use a LayerLink, but use just the position and size, but not the scale."... then I could easily implement the Figma Style UI above. Now I have a head-ache after diving into LeaderLayer, ContainerLayer, CompositedTransformFollower and RenderFollowerLayer, and still don't feel like I have any clue the answer to my Q.
I was really just hoping LayerLink was a ChangeNotifier I could bind to, with Pos, Size, and Scale values, which is really all I need to implement my own in-stack Overlay in a clean and simple way, or do my own positioning within the OverlayEntry, rather than relying on CompositedTransformFollower which is doing things I don't really want.
For now I just have to abandon that approach because the overall system would take weeks of dedicated study to understand deeply.
Another thing to note, even though something like  this should be handled by an overlay-like widget, having it tied to Navigator is problematic. Often, we want to be able to control the sorting order of our Overlays. For example, the Figma "Selection Box: UI will overlay all items within the "Artboard Area" but it will not overlay the panels of the app itself:

To do this in Flutter with Overlay, you need nested Navigators. This is an invasive and undesired requirement. With a simple LayerLinkDispatcher and a parent Stack, we could achieve the result we need very simply.

Just to try and gather this all in one place, I believe there's about 158 upvotes on this general issue:
There is this one, with 113 votes, which is basically asking for this ability (despite the title asking for docs), closed without resolution.
https://github.com/flutter/flutter/issues/19445
This one from 2 yrs ago, with 25 votes, still open
https://github.com/flutter/flutter/issues/31728
This issue with 20 votes, which is making the same request, closed without resolution
https://github.com/flutter/flutter/issues/27587
It just seems to be a repeated cycle of developers saying this is needed to avoid ugly hacks, Flutter team asking for examples, then being un-moved by the examples.
The simple argument this makes our code cleaner, more robust, and easier to debug a lot of the times. It's both a quality of life thing, but also a elegance thing, the alternative is almost always more LOC, more complexity and more time.

What a delight to see this issue moving forward! I've been asking for this feature for over a year. I think the proposed solution would solve most of our issues regarding hit testing. 😊

Looking forward for the solution :)

Here's a use case to get the ball rolling.
This shows 2 issues with flutter layout currently:

Hit areas can not extend outside their parent
The size of the child is also clipped

This is a classic, desktop-style dropdown menu, in 65 lines.
https://user-images.githubusercontent.com/736973/111880626-2d0c7400-8972-11eb-9440-adf912a6e8be.mp4
// Shows 3 buttons, when rolling a menu should pop up below the button.
class DropDownMenuSpike extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      Row(
        children: [MenuBtn(), MenuBtn(), MenuBtn()],
      ),
      Expanded(child: Center(child: Text("PAGE CONTENT")))
    ]);
  }
}

class MenuBtn extends StatefulWidget {
  @override
  _MenuBtnState createState() => _MenuBtnState();
}

class _MenuBtnState extends State<MenuBtn> {
  bool _isMouseOver = false;

  @override
  Widget build(BuildContext context) {
    MouseRegion addMouseRegion(Widget child) => MouseRegion(
        child: child,
        onEnter: (_) => setState(() => _isMouseOver = true),
        onExit: (_) => setState(() => _isMouseOver = false));
    Color bgColor = Colors.black.withOpacity(_isMouseOver ? .3 : .1);

    return Container(
      width: 100,
      height: 40,
      color: bgColor,
      child: Stack(
        children: [
          // Main Btn
          addMouseRegion(Center(child: Text("MenuBtn"))),
          // Dropdown Menu
          if (_isMouseOver)
            Transform.translate(
              offset: Offset(0, 30),
              child: addMouseRegion(DropDownMenu()),
            )
        ],
      ),
    );
  }
}

class DropDownMenu extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 200,
      color: Colors.black.withOpacity(.2),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextButton(onPressed: () {}, child: Text("CLICK ME IF YOU CAN!")),
          TextButton(onPressed: () {}, child: Text("CLICK ME IF YOU CAN!")),
          TextButton(onPressed: () {}, child: Text("CLICK ME IF YOU CAN!")),
        ],
      ),
    );
  }
}

As written, I don't see any reason why this shouldn't just work. Seems rather clear on it's face: when we mouse over, we show a Column of btns, we offset it by our own height on the Y-axis, dropdown menu is done? And importantly, the code the actually show-hide the menu here is what, 3 or 4 lines? The rest is just content.
This is simple, elegant, portable, composable and easy to maintain. The alternatives are all more cludgy:

Make DropDownMenuSpike aware of the dropdown menu positioning
Create a wrapper widget (stack) to coordinate between the btns and the popovers
Use overlay,

None of these are appealing when the above KISS code should do the job. Actually they are all a source of potential bugs and will be harder to maintain, and harder for other team members to grok.
A note on child bounds/clipping
I think this hit test outside of parent bounds fixes part of this issue. But what are we supposed to do about the size of our offset elements if they are bigger than tne parent?
I always try to use UnconstrainedBox here, but it works in really bizarre ways. For example, if I use it here, I have to offset by 60px, instead of 40, to get the correct positioning (wat?)

Something like IgnoreParentBounds that respected parent positioning, but did not enforce any bounds on the size of the child, or the hit test bounds of the child would be perfect.
Then at any time, in any widget we can just make a Stack, wrap some thing in IgnoreParentBounds, and translate it anywhere we need.

Another example from a realworld use case we've had in the past.
A custom auto-complete in 63 lines, using the offset trick + inverting column order:
https://user-images.githubusercontent.com/736973/111886459-32c68180-8993-11eb-8149-b68cb9c10f5d.mp4
class SearchResultsSpike extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      // invert column direction so the SearchBox sits on top
      verticalDirection: VerticalDirection.up,
      children: [
        Flexible(child: Center(child: Text("PAGE CONTENT"))),
        ExpandingSearchBox(),
      ],
    );
  }
}

class ExpandingSearchBox extends StatelessWidget {
  final ValueNotifier<String> _textNotifier = ValueNotifier("");
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _textNotifier,
      builder: (_, __) {
        String value = _textNotifier.value;
        return SizedBox(
          height: 60,
          child: Stack(
            children: [
              // Search Box
              TextFormField(onChanged: (value) => _textNotifier.value = value),
              // Search Suggestions Dropdown
              if (value != "")
                Transform.translate(
                  offset: Offset(0, 60),
                  child: OverflowBox(
                    alignment: Alignment.topLeft,
                    maxHeight: 400,
                    child: _SearchResults(query: value),
                  ),
                )
            ],
          ),
        );
      },
    );
  }
}

class _SearchResults extends StatelessWidget {
  final String query;

  const _SearchResults({Key? key, required this.query}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Container(
        width: double.infinity,
        color: Colors.grey.shade100,
        child: Column(
          children:
              List.generate(query.length, (i) => TextButton(child: Text("Some Suggestion... "), onPressed: () {})),
        ),
      ),
    );
  }
}

Note that only 6 lines here concern themselves with position of this dropdown in relation to the TextField, everything else is content. And we could drop that to 2 lines or so by making a little wrapper for Translate + OverflowBox:
verticalDirection: VerticalDirection.up,
...
OverlayedWidget(offset: Offset(0, 60), maxHeight: 400, child: _SearchResults(query: value))

The simplicity is the win here.

Another really nice addition, which would remove the cludge around column direction, would be an OverlayedWidget:
return OverlayedWidget(child:  _SearchResults(query: value)); // gets sorted above all Widgets, but underneath Overlay

Allowing us to create overlay-like things, without all the complexity of Overlay.
If things in the OverlayedWidget layer had unbounded hit tests, and sorted 1 layer above the normal widget layer, that could get us a lot of what we need. Though there are still use cases for thing sliding out from underneath other layers, so the general purpose IgnoreParentPointerBounds would still be needed.

Here is another example. A figma style selection box in 84 lines:
https://user-images.githubusercontent.com/736973/111888736-e84e0080-89a4-11eb-8178-37c2832994ae.mp4
This shows how we can have good encapsulation by not having the parent know or care about any controls in the negative margins of it's box. This box may have big fat controls for tablet, small controls for desktop, maybe it has panels that may or may not show up depending on content type, the parent does not, and should not, care about any of that, it just knows this box is 200w/200h and positioned at 200x/200y.
It also shows a technique, that I believe is impossible with Overlay, which is counter-scaling our overlayed content so it can maintain a consistent size. Note in the video below that the border always appears to be 1px, and the handles are 10px, regardless of the scale of their parent.
class _FigmaSelectionSpikeState extends State<FigmaSelectionSpike> {
  late final TransformationController _controller = TransformationController()..addListener(_handleTransform);

  @override
  Widget build(BuildContext context) {
    return InteractiveViewer(
        transformationController: _controller,
        boundaryMargin: EdgeInsets.all(double.infinity),
        child: Container(
          width: 1000,
          height: 1000,
          child: Artboard(parentScale: _controller.value.row0[0]),
        ));
  }

  void _handleTransform() => setState(() {});
}

class Artboard extends StatelessWidget {
  const Artboard({Key? key, required this.parentScale}) : super(key: key);
  final double parentScale;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(color: Colors.grey.shade300),
        Transform.translate(
          // Position the Box at it's true position and size
          // We intentionally don't want to know about the "hanging" ui,
          // this is Box's problem.
          offset: Offset(200, 200),
          child: Container(
            width: 200,
            height: 200,
            child: ContentBox(isSelected: true, uiScale: parentScale),
          ),
        )
      ],
    );
  }
}

class ContentBox extends StatelessWidget {
  const ContentBox({Key? key, required this.isSelected, required this.uiScale}) : super(key: key);
  final bool isSelected;
  final double uiScale;

  @override
  Widget build(BuildContext context) {
    Widget scale(double value, Widget child) => Transform.scale(scale: value, child: child);
    double btnSize = 10;
    return Stack(
      clipBehavior: Clip.none,
      children: [
        // Background
        Container(color: Colors.white),

        // Box can overhang its UI, in any way it wants, no one else knows or cares
        if (isSelected) ...[
          Container(decoration: BoxDecoration(border: Border.all(width: 1 / uiScale, color: Colors.red))),
          Positioned(right: -btnSize / 2, top: -btnSize / 2, child: scale(1 / uiScale, _Handle(btnSize))),
          Positioned(left: -btnSize / 2, top: -btnSize / 2, child: scale(1 / uiScale, _Handle(btnSize))),
          Positioned(right: -btnSize / 2, bottom: -btnSize / 2, child: scale(1 / uiScale, _Handle(btnSize))),
          Positioned(left: -btnSize / 2, bottom: -btnSize / 2, child: scale(1 / uiScale, _Handle(btnSize))),
        ]
      ],
    );
  }
}

Widget _Handle(double size) => Container(
    width: size,
    height: size,
    decoration: BoxDecoration(color: Colors.white, border: Border.all(color: Colors.red)),
    child: TextButton(
      style: ButtonStyle(visualDensity: VisualDensity.compact, padding: MaterialStateProperty.all(EdgeInsets.zero)),
      onPressed: () {},
      child: Container(),
    ));

@esDotDev Thanks so much for taking the initiative here, I've been following this issue for a while now. I'm trying to implement a Figma-style layout in a production app, and can't perform hit-tests of widgets outside the bounds of my Stack within an InteractiveViewer.
I've tried implementing overlays as a solution to no avail - fairly certain they can't be used to fit my use-case, and the one you've outlined above.
Would love to see a solution to this implemented so that I don't have to dive into RenderObjects.

I have 2 points to add that speak against this feature:

Hit testing and painting is intuitive and easy to debug the way that it works right now. You paint in one direction, you hit test in the other. Overlays just lay on top of everything. I can't think of any exceptions to that. I believe this change would make that unnecessarily complicated to understand and debug.
Having a stack with a bunch of widgets to implement complex UI elements is easy, but it is not efficient. It trades performance for ease of use.

In my opinion, the solution to this issue is already in this thread:

Obviously that would in general be expensive [...] I think ~we would~ you should still avoid doing this ever [...] since it's better to adjust the widget hierarchy to not have ancestors of the transformed widget be smaller than that widget [...]

That, and a lot more documentation, especially examples around RenderObjects and the Flow^ widget would solve this issue.

To those who want to implement a Figma like view
You will run into problems when your Stack contains widgets that are not visible. You need RenderObjects to conditionally create and destroy widgets. Or at least a Flow^ widget to conditionally paint a subset of them.
InteractiveViewer is not made for the things that people use it for
This is a huge problem because it will disappoint those who try to use it for that.
Flutter supports tens of thousands of inflated widgets in one view, with hundreds of widgets in one viewport and can still reach 200FPS+ You will never be able to achieve this with a Stack (and an InteractiveViewer). This is not an issue with InteractiveViewer or with Widgets, it's just that all abstractions have a performance limit. People should be taught to not be afraid of RenderObjects.

but the cost (which affects every app) might still be worth it?

No!

^ Not many people know of the Flow widget. It is a more powerful version of a Stack.  https://api.flutter.dev/flutter/widgets/Flow-class.html. It could solve some of the problems that people are facing here.

That Flow widget looks really cool, 18mths with Flutter and this is the first I've ever heard of it.

From my experience what most devs find intuitive, is "if something is visible, and not covered by something else, I can click it", the idea of an invisible box that just cuts off your hit-testing is very non-intuitive. I mean, HTML, Unity, Flash they all act this way.

I don't see what that has to do with this issue. Most stacks we use render less than a dozen items, it wouldn't make sense to use a lower-level API, and we still want this flexibility in regards to hit testing.

I don't understand the argument against extra flexibility. You could simply not use the Widget if you choose.

it's just that all abstractions have a performance limit.

While this is true, its also not meaningful. An abstraction layer can't simply throw up it's hands and say, not my fault. Not every abstraction layer would not have this massive delta in performance.
The idea that we can't simply position something, with an X/Y coords in a few lines, and expect decent performance, in 2021 does not ring true to me at all, knowing how powerful these devices all are.

I mean, HTML, Unity, Flash they all act this way.

FWIW, HTML pays a huge perf cost for this, it's one of the reasons we avoided it in Flutter. (Dunno about the others. Given my experience in Tabletop Simulator, Unity hit testing is a huge mess, but I don't know if that's TTS or Unity!)

In general, I don't understand the argument against extra flexibility. You could simply not use the Widget if you choose.

You might have accidentally skipped the third paragraph of Hixies issue description:

[...] Having to check that flag every step of the walk would itself be not cheap, but the cost (which affects every app) might still be worth it?

Or in other words: Flutter would become slower for everybody if this feature would be implemented. That's why one could not just not use it.

@esDotDev you mention many things that are worth a comment. I can't put too much time into discussions like that right now, I'm sorry for that, I hope you don't mind that.
_If Flow isn't enough for you and you're not afraid to get dirty, Flutter has a hidden, powerful secret weapon stashed in its commit history.
Auto Layout! :)
https://github.com/flutter/flutter/pull/7350/commits/04c82a743d64ff94e171321e5b01d5f39e00791e_

For building a Figma-like view, if I opt for Flow is it okay to pair this with InteractiveViewer? Or should I suck it up and use RenderObject?

For building a Figma-like view, if I opt for Flow is it okay to pair this with InteractiveViewer? Or should I suck it up and use RenderObject?

I'm sorry, but It's impossible to say from the outside, but maybe just go with the Flow and see if that would solve this issue for you first.

This issue really doesn't all come down to a Figma-style view. I've been developing complex UIs and this really comes up every time, even in simpler cases like a custom autocomplete widget (and no, Overlay is not always a viable solution). You often have to rethink your layout entirely for a little 5px margin that you would want to be hittable, this is really not practical. I don't have enough time to enumerate all the cases I've come across (thx @esDotDev) but really insist that this opt-in mechanism should be implemented.

You might have accidentally skipped the third paragraph of Hixies issue description:

Ah, I did miss that point. Well we would need to quantify this before we can have any real discussion about it I think. Or hopefully come up with a solution that doesn't impose a tax on users who haven't opted in.

This issue really doesn't all come down to a Figma-style view.

Exactly. It's a very handy tool for many tasks, it would be nice if we could use it.
People proposing alternate solutions with Flow or Overlay, have to grapple with the fact that  my 3 examples above use <5 lines to do layout, and your proposals are 10-20x more code. This can't be hand-waved away and un-important, or devlopers being lazy, there are tons of tangible benefits to writing and maintaining less code.

@esDotDev you mention many things that are worth a comment. I can't put too much time into discussions like that right now, I'm sorry for that, I hope you don't mind that.
If Flow isn't enough for you and you're not afraid to get dirty, Flutter has a hidden, powerful secret weapon stashed in its commit history. Auto Layout! :) 04c82a7

No worries at all, I have already learned loads from your 2 posts. Thanks!

I don't know that the opt-out mechanism described here is the way to go, but there was a request for use cases above so I'll add one: wanting a small tappable widget to 'slide out from behind' another widget (like a drawer that pulls out and doesn't take up 'physical space').
The natural way to implement this seemed to me to be to put the drawer behind the main widget in a Stack, and then have a SlideTransition animate it out when needed. This works just fine visually, but the sliding drawer doesn't detect hits because of the behaviour described here and elsewhere.
Using Overlay to get around this seems rather awkward to me, since one then needs to clip the drawer separately during the animation. Perhaps there are other nice ways of doing this, however, and I'd be happy to hear about them.

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  late final AnimationController _controller = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 1),
  )..repeat(reverse: true);
  late final Animation<Offset> _offset = Tween<Offset>(
    begin: Offset.zero,
    end: const Offset(0.0, 1.0),
  ).animate(CurvedAnimation(parent: _controller, curve: Curves.ease));

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Container(
        color: Colors.white,
        alignment: Alignment.center,
        child: Stack(
          alignment: Alignment.bottomCenter,
          children: [
            Positioned(
              bottom: 0.0,
              child: SlideTransition(
                position: _offset,
                child: GestureDetector(
                  onTap: () => print("Sliding drawer was tapped"),
                  child: Container(
                    color: Colors.blue[100],
                    child: Text("I slide out from behind", style: const TextStyle(fontSize: 16.0)),
                  ),
                ),
              ),
            ),
            Container(
              width: 300,
              height: 100,
              color: Colors.blue[300],
            ),
          ],
        ),
      ),
    );
  }
}

If we add a shadow to the main Container, which is fairly natural in the 'drawer' scenario, I don't quite see how to achieve this with Overlay (assuming we want to keep the main widget in the main tree). No doubt it wouldn't be a problem with a custom RenderObject, but that's a lot more code.

@olof-dev That's what I was talking about. This is the kind of example that is close to impossible to implement using an Overlay. This proposition could be accepted for this reason only.

Ya the shadow example in particular show-cases the flexibility of this technique. We will often get subtle designs like this from Design Team, and it is very important to them that a shadow sorts properly.
Essentially this technique gives developer more flexibility in sorting, whereas Overlay has only one sorting behavior and no ability to interleave the "follower" with the "target".
More flexible and less code!

@Hixie Can the name of this issue be changed? I feel like it is not gaining enough traction as other issues reporting a similar problem because it isn't obvious about what it means for beginner flutter developers.

Its also the 3rd or 4th post on this issue, the others had dozens of
upvotes that have basically been lost.
On Sat., Jun. 19, 2021, 4:26 a.m. Nathan Cabasso, @.***>
wrote:

@Hixie https://github.com/Hixie Can the name of this issue be changed?
I feel like it is not gaining enough traction as other issues reporting a
similar problem because it isn't obvious about what it means for beginner
flutter developers.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/flutter/flutter/issues/75747#issuecomment-864387390,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAFT5TORYVEOL4D32G2QID3TTRWEPANCNFSM4XL7AH4A
.

The reality is this one might be closed as well. The suggestions in the original comment aren't really viable in practice, I just listed them to see if we could get some ideas for how to do it. But we haven't really gotten any.

So, is there any plan to address this limitation at all? We've listed 2 or 3 use cases, that while totally straightforward and expected from our designers POV, becomes literally impossible with Overlay.
Specifically

sorting "pop-outs" with shadows as you would typically expect,
having a consistently sized overlay while the parent zooms, for example a 1px border around a box, as the box itself is scaled (seen in every design tool out there, Figma, XD, Sketch etc).
having many overlays that should interleave the content (multiple boxes, with selection outlines, that are still sorted, again, like Figma, XD etc all do)

It's pretty frustrating, as flutter teams asks here" are then any use cases that would be simplified with this approach", many use cases are provided which clearly benefit from this approach, and then the issue is just closed anyways.
It seems to point to some flaw in how github issues are used to determine priorities. No matter how many issues are raised, or upvotes cast, it seems like this is just never going to change. I think at this point the community is just running out of energy pushing this, will give up, and Flutter just lives with this unfortunate limitation forever, which is extremely unfortunate imo.

sorting "pop-outs" with shadows as you would typically expect,

This sounds like the same kind of thing as what we do with toolbars in text fields, which we do with Overlay. Unless you are referring to changing the order of the entries in the overlay? In which case I would probably recommend just making your own Overlay-like widget, or indeed just using a Stack (Overlay is basically just a Stack with an imperative API, after all), where you can control whatever you want.
I certainly would not recommend doing pop-outs using a hitTestSelf culling opt-out even if Flutter provided it. It would be really expensive to do it that way.

having a consistently sized overlay while the parent zooms, for example a 1px border around a box, as the box itself is scaled (seen in every design tool out there, Figma, XD, Sketch etc).

Not sure I understand what you mean here. Do you have a screenshot?

having many overlays that should interleave the content (multiple boxes, with selection outlines, that are still sorted, again, like Figma, XD etc all do)

Sorry I'm not familiar with Figma or XD. This sounds like something that I'd probably approach with custom RenderObjects though. I mean, any time you are really designing custom bespoke layouts, that's really what Flutter expects you to do.

It's pretty frustrating, as flutter teams asks here "are there any use cases that would be simplified with this approach", many use cases are provided which clearly benefit from this approach, and then the issue is just closed anyways.

Oh I totally agree that there are use cases, that's why I filed this bug. There being use cases is a reason for us to look at a problem. There also have to be reasonable solutions if we're to implement them, though. This specific issue is narrowly focused on some potential solutions that could be a way to resolve a particular set of use cases, but there's lots of other ways unrelated to hit testing for solving those use cases.

It seems to point to some flaw in how github issues are used to determine priorities. No matter how many issues are raised, or upvotes cast, it seems like this is just never going to change. I think at this point the community is just running out of energy pushing this, will give up, and Flutter just lives with this limitation forever, which is extremely unfortunate imo.

When we created Flutter, we made some design decisions that will bake in limitations. For example, we use Dart. We don't use TypeScript. So if the limitation is "Flutter requires Dart", then yes, we're unlikely to change that. Similarly we decided early on to never address vertical text requirements. This allowed us to make massive simplifications to our API design, but it means that certain Japanese use cases (for example) aren't something Flutter will ever be good at. Another example is that we decided to fix a huge performance problem with web browsers around hit testing, by doing hittest culling. I filed this bug because I thought it would be worth reexamining this if we could find efficient solutions that avoided this, but at the end of the day, we have not found more efficient ways to do hit testing that don't do culling.
Something being high priority doesn't mean it gets done, if there's no solution that addresses all the constraints.
Also, as far as I'm aware, all the use cases that have been brought up for removing hit test culling are quite possible if you design the application with hit test culling in mind. So it's not like this is preventing people from writing apps, it's just requiring that people design their apps a little differently than they might do when designing them for other systems. (Notably the web; most other systems actually do do hit test culling as well. It may be less obvious in some cases because in most systems the tree is extremely shallow.)

Worth mentioning that this "expensive" hit test, to date, has never been quantified in any way. Which seems a rather important first step to evaluating anything...

An easy way to see how expensive hit testing is is to profile Flutter desktop applications when you casually move the mouse over the window. It's almost always the top of the profile. We're spending way more time hit testing today than I'm comfortable with, frankly. (I wish we could just remove hover support, but sadly that's a non-starter on desktop.) Making hit testing more expensive (by moving it from O(N) in depth of tree to O(M) in nodes in the tree, which can be multiple orders of magnitude bigger) is just not practical.
You could easily test this yourself. Remove the culling logic from the framework, and compare how long hit-testing takes before and after.
If you have specific use cases that you can't solve, or for which you think the framework should provide a solution (as opposed to a package providing the solution), then you should feel free to to file bugs on those use cases. I would recommend not trying to describe the preferred solution as part of describing the problem, though, as you will get more traction if you explain that you can't figure out how to do something than if you say "this particular API is preventing me from doing something". (Because it's easy to say "no it isn't" to the second, but hard to deny the first without providing an example.)

An easy way to see how expensive hit testing is is to profile Flutter desktop applications when you casually move the mouse over the window. It's almost always the top of the profile. We're spending way more time hit testing today than I'm comfortable with, frankly. (I wish we could just remove hover support, but sadly that's a non-starter on desktop.) Making hit testing more expensive (by moving it from O(N) in depth of tree to O(M) in nodes in the tree, which can be multiple orders of magnitude bigger) is just not practical.

I'm having trouble understanding this. We are asking for a way to make a specific Widget hittable globally, without needing it to be in its parents bounds. Wouldn't this require only to loop on those few specific Widgets to check if it gets hit? I don't understand how this could be O(M) with M = number of nodes on the tree.

"So it's not like this is preventing people from writing apps" - In a world without timelines, and requirements that are fully known in advance, this might be true, but this world doesn't exist.
In reality, when things are slow cludgy to implement, or have to be "planned for" months in advance to not be a total mess, the feature just gets cut, or the design gets downgraded.
I understand that not everything is possible, but this is a basic ask from an end user perspective, it's not analogous to switching to dart, or asking for vertical text. We haven't even done the basic step of testing these hit tests to see the magnitude of what we're talking about, so I don't see how any of the proposed solutions can really be dismissed. What exactly is "expensive"?

In reality, when things are slow cludgy to implement, or have to be "planned for" months in advance to not be a total mess, the feature just gets cut, or the design gets downgraded. So this very much does stop features and design from being built, if not entire apps.

This. I cannot count the number of time I had to ask the designer to rethink the UI because it was just too hard to do it in Flutter whereas the same exact feature is implemented on the web very easily. Flutter plays nicely with Material, but I work with complex UIs and this specific issue is the only thing that makes integration hard in my opinion.

Not really sure where to start here, there's 10's of thousands of lines of code in the FlutterSDK. Happy to play with it if you can point me in the right direction.

I would also be happy to help, a detailed explanation of how this could be done would be much appreciated! I have multiple ideas on how to do it efficiently in my head but I don't know Flutter architecture enough to do it on my own.

This issue still seems to be open, and accurately describes the problem, so I don't think there's need for a new issue.
While tweaks to Overlay would be nice, to support some edge cases, what we really are missing is a simple way to expand the hit area x pixels: https://github.com/flutter/flutter/issues/31728
The bummer is that this issue should have more like 150+ likes, if you combine all the issues that are complaining about the same thing.
fwiw, there is a package now that seems to do the job, referenced in that post:
https://pub.dev/packages/expand_tap_area
@Hixie Maybe this could inspire some ideas within the team on a way to tack this? Seems to use a custom GestureArenaMember with some negative offsets.
Notably, within the source code, we find this comment:
// If there is someone who knows how to extend the hitarea above the parent rect, so it is not
// Clipped, please add that here. This would be really helpful.
https://github.com/malikwang/expand_tap_area/blob/master/lib/src/expand_tap_area.dart

@Vardiak

An easy way to see how expensive hit testing is is to profile Flutter desktop applications when you casually move the mouse over the window. It's almost always the top of the profile. We're spending way more time hit testing today than I'm comfortable with, frankly. (I wish we could just remove hover support, but sadly that's a non-starter on desktop.) Making hit testing more expensive (by moving it from O(N) in depth of tree to O(M) in nodes in the tree, which can be multiple orders of magnitude bigger) is just not practical.

I'm having trouble understanding this. We are asking for a way to make a specific Widget hittable globally, without needing it to be in its parents bounds. Wouldn't this require only to loop on those few specific Widgets to check if it gets hit?

The difficulty is that without walking the tree, you don't know which widget is on top when two of your specific widgets overlap.
If you don't care (e.g. because you know your widgets never overlap) you can do this today by hooking into the pointer router at the top level and, checking the pointer against the widget's bounds. No need for anything new in the framework to do that.

This. I cannot count the number of time I had to ask the designer to rethink the UI because it was just too hard to do it in Flutter whereas the same exact feature is implemented on the web very easily. Flutter plays nicely with Material, but I work with complex UIs and this specific issue is the only thing that makes integration hard in my opinion.

If there are specific UIs that are too hard to do in Flutter, please file a bug describing that UI. (Don't file a bug asking for a specific solution, like "expand hit-test areas", file a bug for the specific UI you're trying to build.)

Not really sure where to start here, there's 10's of thousands of lines of code in the FlutterSDK. Happy to play with it if you can point me in the right direction.

I would also be happy to help, a detailed explanation of how this could be done would be much appreciated! I have multiple ideas on how to do it efficiently in my head but I don't know Flutter architecture enough to do it on my own.

The hit testing system is documented pretty heavily, see e.g. RenderBox in the API docs.
The code that does the filtering I'm talking about is typically in hitTest, e.g. RenderBox.hitTest (that one provides the default implementation for most RenderBox subclasses). If you look at that function you'll see it only calls hitTestChildren if the position is inside size. Remove that check, and it'll walk the entire tree and all children will check their bounds without paying attention to the parent.
To benchmark it, do that in some complicated application, and then time how long it takes to call binding.hitTest thousands of times with random offsets, and compare to the performance with the check present.

I am late to this discussion, and this proposal may make no sense at all, but how about we have these 2 widgets:

A new HitTestAll widget, where all widgets below it would call their children hit test. So the developer could choose the specific subtree they want to pay the performance hit.

The GestureDetector widget could have a hitMargin parameter to expand its hit test area.

So for example, if I want some text in a row to have a 20 pixel larger click-area I could do:
HitTestAll(
  child: Row(
      children: [
          Text('abc'),
          Text('123'),
          GestureDetector(
               onTap: onTap,
               hitMargin: EdgeInsets.all(20),
               child: Text('Click me'))

A new HitTestAll widget, where all widgets below it would call their children hit test without further culling. So the developer could choose the specific subtree they want to pay the performance hit.

The problem is that it is not possible (as far as I can tell) to create such a widget without taking a performance hit even if it's not used, because every widget would need to check whether it was inside such a subtree all the time (even when not in such a subtree).

The GestureDetector widget could have a hitMargin parameter to expand its hit test area.

Similarly here, it doesn't seem to me to be possible to implement this without it affecting every widget (technically every render object) because it requires all the hit test logic for nodes above the GestureDetector in the tree to cooperate. Currently, the gesture detector's hit test area is literally the biggest it can be according to its parent. So without cooperation from the parent, it can't be made bigger.
That said, I could be wrong. If there's a way to implement these widgets, I would encourage you to create a package that contains them. It would be a popular package if this issue is anything to go by. :-)

@Hixie @esDotDev

because every widget would need to check whether it was inside such a subtree all the time (even when not in such a subtree).

Can't we send this information (if it's inside such a subtree or not) down, through the hitTest method?
This is the current hitTest signature:
bool hitTest(BoxHitTestResult result, { required Offset position });

It could have an expandArea boolean:
bool hitTest(BoxHitTestResult result, { required Offset position, required bool expandArea});
    if (expandArea || _size.contains(position)) {
      if (hitTestChildren(result, position: position, expandArea: expandArea) || hitTestSelf(position)) {
        result.add(BoxHitTestEntry(this, position));
        return true;
      }}}

The expandArea parameter would be false until it encountered the HitTestAll widget, which would simply change it to expandArea: true:
bool hitTest(BoxHitTestResult result, { required Offset position, required bool expandArea}) {
    if (expandArea || _size.contains(position)) {
      if (hitTestChildren(result, position: position, expandArea: true) || hitTestSelf(position)) {
        result.add(BoxHitTestEntry(this, position));
        return true;
      }}}

One can't really create a package with these features because it means changing the hitTest method.

What you describe is exactly what I am referring to when I say "every widget would need to check whether it was inside such a subtree all the time".

@Hixie Ah, ok. I was thinking you meant that each widget would have to go up the tree to search for an ancestor, somehow. That could potentially be slow.
What I've described means having to pass an extra parameter to the method that already exists and checking a boolean for each widget. This:
if (expandArea || _size.contains(position))

Instead of this:
if (_size.contains(position))

Even in a very large tree, if we have, say 10,000 widgets to check, I'd say that's extremely fast. I can create some code to actually measure it, if you want.
Also, I'd say that even if Flutter doesn't want to provide a widget like the HitTestAll widget I've described above, changing the hitTest method would allow package authors to create widgets that opt out of the hit test culling, just as you have suggested.

Sure, that one boolean check wouldn't make a noticeable difference. However, the general policy of whether or not we add such features applies to many more places than just this check. If we have the general policy of adding features like this, then there would be many, many more places where we would add such checks. Together, they would be noticeable.
So we have three choices: add this feature because we have a policy of adding such features, add this feature in violation of our policy of not adding such features because it's an exception that deserves special consideration, and not add this feature because we have a policy of not adding such features.
It's only by being really rigorous in applying such policies that we can maintain performance across the board., so our bar for violating the policy is a very high one. Considering whether this meets that bar is why I filed this bug in the first place, but so far I don't think this is an unusually compelling case given that there are workarounds available (albeit unpleasant ones).

Everyone will have their own list of what deserves special consideration, but I don't think you get much more integral than hit testing. It's the foundation of virtually all interaction with the devices. It is certainly right at the very top of my list for "Frustrating pain points in flutter". The community seems to have put in a lot of effort to create code examples to demonstrate the issue, and poured in hundreds of votes over the years.
I think this raises an interesting question of how we get past impasses like this. Where the community clearly wants/needs something, but the team seems reluctant to move on it, and we just stall out. I wonder how it can really be decided what "deserves special consideration"?

@Hixie Well, I don't know the policy you are talking about, so I can't comment on how this issue fix would affect it.
It's just that I keep seeing people complaining about this specific issue. For example: https://github.com/flutter/flutter/issues/19445 and also this https://github.com/marcglasberg/align_positioned/issues/7
And also these workarounds to expand the tap area make my code ugly. I create some really nice clean code and then I have to make it ugly to expand the click-area. It just feels unnatural.
And there is at least one use case I can't fix with current workarounds. If we have some text and in the middle of it there's a link. I'd like to expand the link area, but I don't know where it's going to be printed because it's a very complex calculation I can't perform myself.
Please note, there is already a package that would start working properly if the hitTest method were changed:  https://pub.dev/packages/expand_tap_area

I don't think there's any disagreement that this is something we'd like to make better. I mean, I filed this bug!
We're just trying to find a way to fix it that doesn't involve a performance hit.

I think this raises an interesting question of how we get past impasses like this. Where the community clearly wants/needs something, but the team seems reluctant to move on it, and we just stall out. I wonder how it can really be decided what "deserves special consideration"?

The community is not a monolithic entity (nor is the team). It's not really useful to frame this as an "us vs them" situation. People care very much about performance too. People care very much about how Flutter's widgets are self-contained and how the protocol between widgets and render objects is simple. We're all in this together, trying to find a design that can address people's needs without compromising on these other priorities.

Well, I certainly agree those things you mentioned are important. In any case, if the Flutter team decides that the proposed change in the hitTest method would be enough to address this issue, let me know if you need measurements on how it would affect performance. Thanks.

@marcglasberg if you find yourself motivated, it would be interested to see those perf numbers if for no other reason than to convince ourselves that we're right not to add this feature.

@csells Well, I would fell motivated only if the proposed change in the hitTest method was considered the solution to the issue, pending only the numbers (the performance hit). But, if as you say the team has already decided not to add the feature for other reasons, it's ok for me.

Its really quite hard to implement these sorts of deep changes to the framework and then accurately measure the cost. It's a tough task to start modifying such a complex system you are not intimately familiar with.
Also, once implemented, measuring the performance of such a tiny change also seems like it would be extremely challenging if you're not deeply knowledgeable on benchmarking in Flutter. Even in simple loops, with 10m iterations, I struggle to measure any consistent cost to a simple bool check. Either the compiler is optimizing things out, or the dart is stupid fast when it comes to comparing bools.
The team is really in a much better position to run some tests, and come back with a number for the cost here, and then we would have real numbers to discuss, vs some undefined idea of "cost".
For example, if it turns out that 10,000 bool checks, are <.01ms on a mid-tier ARM processor, would this discussion be moot? It seems like the order of magnitude should matter here, and be the first data point we need before any potential solution can be considered.

@esDotDev I don't think it's that hard. If you copy the Stack and RenderStack code and modify the hitTest method, then you can create an arbitrarily large wide/deep random tree of those stacks inside of stacks. Then you hit test random locations a million times comparing the time it takes for each different hitTest method.
I'd compare those:
The current one:
bool hitTest(BoxHitTestResult result, { required Offset position});
    if (_size.contains(position) {
      if (hitTestChildren(result, position: position) || hitTestSelf(position)) {
        result.add(BoxHitTestEntry(this, position));
        return true;
      }}}

No culling at all:
bool hitTest(BoxHitTestResult result, { required Offset position});
      if (hitTestChildren(result, position: position) || hitTestSelf(position)) {
        result.add(BoxHitTestEntry(this, position));
        return true;
      }}

Selective culling (the proposed solution)
bool hitTest(BoxHitTestResult result, { required Offset position, required bool expandArea});
    if (expandArea || _size.contains(position)) {
      if (hitTestChildren(result, position: position, expandArea: expandArea) || hitTestSelf(position)) {
        result.add(BoxHitTestEntry(this, position));
        return true;
      }}}

hi all, going to go ahead and poke this discussion again. i've been looking into this a bit because i'm trying to create some humble dropdowns for a desktop app (see some of my misadventures above). i potentially have a solution that will work for my use case, but i wanted to see what some more knowledgeable flutter folks think and whether there's a way to expand it to other use cases. i'm unclear on both the performance implications and soundness of the approach because i'm still pretty hazy on how the RenderObject life cycle and paint phase work.
the solution is sort of inspired by the CompositedTransform{Target,Follower} widgets and along the lines of what @Hixie mentioned in the original comment of this thread:

Another option might be to have a way for a widget to hook into the hit testing of a far ancestor (e.g. via an inherited widget).

basically there's an ancestor RenderProxyBox which gets a handle to some deep children RenderProxyBoxes, and the ancestor does painting and/or hitTesting instead of the children.

anyway, here's some code:
class DeferredPaintLink extends ChangeNotifier {
  final List<RenderBox> _renderBoxes = [];
  List<RenderBox> get renderBoxes {
    return UnmodifiableListView(_renderBoxes);
  }

  void add(RenderBox deferredPainter) {
    if (!_renderBoxes.contains(deferredPainter)) {
      _renderBoxes.add(deferredPainter);
      notifyListeners();
    }
  }

  void remove(RenderBox deferredPainter) {
    if (_renderBoxes.contains(deferredPainter)) {
      _renderBoxes.remove(deferredPainter);
      notifyListeners();
    }
  }

  DeferredPaintLink();
}

class DeferredPainter extends SingleChildRenderObjectWidget {
  DeferredPainter({required this.link, Widget? child, Key? key}) : super(child: child, key: key);

  final DeferredPaintLink link;

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderDeferredPainter(link);
  }

  @override
  void updateRenderObject(BuildContext context, RenderDeferredPainter object) {
    object.link = link;
  }
}

class RenderDeferredPainter extends RenderProxyBox {
  RenderDeferredPainter(DeferredPaintLink link, {RenderBox? child}) : super(child) {
    this.link = link;
  }

  bool _linked = false;

  DeferredPaintLink? _link;
  DeferredPaintLink get link => _link!;
  set link(DeferredPaintLink link) {
    if (_linked) {
      link.remove(this.child!);
      _linked = false;
    }
    _link = link;
    if (_link != null && this.child != null) {
      link.add(this.child!);
      _linked = true;
    }
  }

  @override
  set child(RenderBox? child) {
    if (_linked) {
      link.remove(this.child!);
      _linked = false;
    }
    super.child = child;
    if (_link != null && this.child != null) {
      link.add(this.child!);
      _linked = true;
    }
  }

  void attach(covariant PipelineOwner owner) {
    super.attach(owner);
    if (!_linked && _link != null && this.child != null) {
      link.add(this.child!);
    }
  }

  void detach() {
    if (_linked) {
      link.remove(this.child!);
    }
    super.detach();
  }

  @override
  bool hitTest(BoxHitTestResult result, {required Offset position}) {
    return false;
  }

  @override
  void paint(PaintingContext context, Offset offset) {}
}

class DeferredPaintTarget extends SingleChildRenderObjectWidget {
  DeferredPaintTarget({required this.link, Widget? child, Key? key})
      : super(child: child, key: key);

  final DeferredPaintLink link;

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderDeferredPaintTarget(link);
  }

  @override
  void updateRenderObject(BuildContext context, RenderDeferredPaintTarget object) {
    object.link = link;
  }
}

class RenderDeferredPaintTarget extends RenderProxyBox {
  RenderDeferredPaintTarget(DeferredPaintLink link, [RenderBox? child]) : super(child) {
    this.link = link;
  }

  DeferredPaintLink? _link;
  DeferredPaintLink get link => _link!;
  set link(DeferredPaintLink link) {
    if (_link != null) {
      _link!.removeListener(this.markNeedsPaint);
    }
    _link = link;
    this.link.addListener(this.markNeedsPaint);
    markNeedsPaint();
  }

  @override
  bool hitTest(BoxHitTestResult result, {required Offset position}) {
    for (final renderBox in link.renderBoxes.reversed) {
      final hit = result.addWithPaintTransform(
        transform: renderBox.getTransformTo(this),
        position: position,
        hitTest: (BoxHitTestResult result, Offset? position) {
          return renderBox.hitTest(result, position: position!);
        },
      );
      if (hit) {
        return true;
      }
    }
    return child?.hitTest(result, position: position) ?? false;
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    super.paint(context, offset);
    for (final renderBox in link.renderBoxes) {
      context.paintChild(renderBox, renderBox.localToGlobal(Offset.zero, ancestor: this) + offset);
    }
  }
}

i have it set up so the ancestor paints the children last and hit tests first because i'm trying to make dropdowns, but you could for example have the children paint themselves, and then have the ancestor hit test them last if they're meant to be hiding behind the rest of the UI. the DeferredPaintLink object could of course be packaged with some widget inheritance to make it an implementation detail, i just wanted to keep things barebones for discussion's sake.

and here's a sample usage:
void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  final link = DeferredPaintLink();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: DeferredPaintTarget(
          link: link,
          child: Column(
            children: [
              Container(
                height: 200,
                child: OverflowBox(
                  alignment: Alignment.topCenter,
                  maxHeight: 400,
                  child: Column(
                    children: [
                      Container(
                        height: 200,
                        child: HitTestWidget(off: Colors.deepOrange, on: Colors.orange),
                      ),
                      DeferredPainter(
                        link: link,
                        child: Container(
                          height: 100,
                          child: HitTestWidget(off: Colors.green, on: Colors.lightGreen),
                        ),
                      ),
                      DeferredPainter(
                        link: link,
                        child: Container(
                          height: 100,
                          child: HitTestWidget(off: Colors.blue, on: Colors.lightBlue),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              Flexible(child: HitTestWidget(off: Colors.amber, on: Colors.yellow)),
            ],
          ),
        ),
      ),
    );
  }
}

class HitTestWidget extends StatefulWidget {
  final Color off;
  final Color on;

  const HitTestWidget({Key? key, required this.off, required this.on}) : super(key: key);

  @override
  State<StatefulWidget> createState() => HitTestWidgetState();
}

class HitTestWidgetState extends State<HitTestWidget> {
  bool flipped = false;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => setState(() => flipped = !flipped),
      child: Container(
        color: flipped ? widget.on : widget.off,
      ),
    );
  }
}

you can remove the DeferredPainters from the sample usage to see how they affect the behaviour. you could also customize whether the ancestor or children do either of the hit testing or painting and in what order to achieve various useful and/or nonsensical effects.
would something like this be useful for anyone else running into this issue? does this have subtle issues which make it a nonviable approach?
thanks for your time, anyone who read all this!

@shrouxm this looks really neat. So basically somehow you have some object at the top of the tree that is able to perform hit-tests for any  renderObject further down the tree, if given the link.
Basically the renderObjects get painted and hit tested on a seperate layer, which sortof acts like a more flexible easier to use Overlay?
Would this still work if I wanted to do something basic, like offset an icon btn slightly outside my bounds?
Column(children: [
  DeferredPainter(child: Transform.offset(child: IconBtn(), offset: Offset(-5, 0))),
])

The ability to not render on top seems really interesting too. Sometimes you have a panel, with a shadow, and you want your dropdown to slide out underneath the shadow. This would support that too I guess, as I could render where I am, but have hit testing performed at the top of the tree?

@shrouxm So far this looks really promising, any idea how I could tweak it to render in place so it can stay under the shadow?
For example, this works nicely, but I need it to sit under the shadow of the sibling container:
Stack(
  clipBehavior: Clip.none,
  children: [
    Positioned(
      bottom: -30,
      child: DeferredPainter(
        link: link,
        child: _SomeBtn(),
      ),
    ),
    Container(
        width: 100,
        height: 100,
        decoration: BoxDecoration(color: Colors.green, boxShadow: [
          BoxShadow(color: Colors.black.withOpacity(1), blurRadius: 4, spreadRadius: 4),
        ])),
  ],
),

https://user-images.githubusercontent.com/736973/141722886-2fc5b719-7631-415e-8910-0b565d86d128.mp4
@Hixie any thoughts on this approach in general? It seems usable, and only incurs performance hits on widgets that ask for it. Basically we have an ancestor widget, that can perform hitTesting and (optionally) rendering for us, allowing us to use some parent as our hit test bounds, but also keep our widget in the display tree if desired, so it maintains existing display order (which serves use cases that overlay does not support)

Also seems like DeferredPaintTarget could just have it's own internal link, and DeferredPainter just looks upwards? Link could become optional?  One single overlay-like surface at the root of the tree is the common case?

Nevermind @shrouxm I figured it out, here's an alternate version that adds a 'drawOnTop` value to the painters:
https://gist.github.com/esDotDev/0f783f1f4ddc318c967328b48bfd3199
With that we get this!
https://user-images.githubusercontent.com/736973/141724789-23731dd2-6350-4b7b-8b8e-31433bc626b0.mp4

@shrouxm I hope you don't mind but I made some small changes and packaged this up:
https://pub.dev/packages/defer_pointer
As far as I can tell it solves all the use cases I can think of:
Offset buttons outside of a stack:
https://user-images.githubusercontent.com/736973/141850225-234f2ac7-afd6-4781-b58c-f78b39f445b2.mp4
A classic desktop style dropdown menu:
https://user-images.githubusercontent.com/736973/141850218-edb47e3a-1422-4471-902c-b23b3e181dfc.mp4
A Flow based widget (which for some reason, needs to use 2 DeferHit widgets, not sure why but it works!)
https://user-images.githubusercontent.com/736973/141850216-aae2434a-f679-446b-9e5c-ddcc96399afa.mp4
A auto-complete example:
https://user-images.githubusercontent.com/736973/141850211-b392f5e4-68d4-4ac2-b103-dc60133e377b.mp4

In general it's plausible but note that linking between nodes in these trees is very bug-prone, you have to be really really careful about managing lifetimes and so on.

@esDotDev i don't mind that you packaged it, although it would be nice if you left a note crediting where the idea came from as the core logic is fairly identical to what i posted. i was thinking of different ways to package it and didn't really settle on a convenient/flexible API. you could for example do full blown z-indexes by making the link hold a SplayTreeMap of lists of render objects indexed over some comparable type. but i don't really think z-indexes are a good idea.
i've only found one bug while using this code since i posted it, the markNeedsPaint() method of the child render object should also call markNeedsPaint() on the parent (if the parent is painting the child and not just doing hit testing,). otherwise a self-contained update of the child render object won't actually repaint on the screen.

@shrouxm attribution added, thanks for the idea! lmk if you want me to change the text, or happy to take any PR's you have

In general it's plausible but note that linking between nodes in these trees is very bug-prone, you have to be really really careful about managing lifetimes and so on.

Thanks for the headsup, can you think of any problematic edge cases I should test? Or just expand on the potential issues? I'm not very familiar with SingleChildRenderObjectWidget lifecycle. Currently descendants just use attach/detach to add/remove themselves from the link.
https://github.com/gskinnerTeam/flutter-defer-pointer/blob/89fd01b9c1cb97b33c1897f7b3d1f70e20688a00/lib/defer_pointer.dart#L80

@shrouxm @esDotDev This is amazing! Exactly what I was looking for. I think this should be added to the framework, and maintained as a non-hacky way to do hit testing.

I agree with it having a nice place in the framework... IgnorePointer, AbsorbPointer, DeferPointer LGTM!

I agree with it having a nice place in the framework... IgnorePointer, AbsorbPointer, DeferPointer LGTM!

About the name: I feel like it wouldn't be clear for and end user what it does, even though it is a good technical term. This is basically global hit testing, and the name should suggest that idea. This would be even simpler if the DeferredPointerHandler is moved inside the WidgetsApp widget (as I understand, there is no performance impact of placing the DeferredPointerHandler higher up the tree).

the performance implication of putting it further up would be unnecessary repaints affecting a larger portion of the app. as far as i understand, inserting a repaint boundary between parent/handler and its primary child should solve this but i haven't tested.
maybe another way to think about it could be via layers? since the repaint boundary would just be creating another layer. i'm envisioning the parent widget accepting a list of keys which will become labels under the scope of that widget for different semantic layers (e.g. maybe a layer for dropdowns, maybe a layer for widgets which only subtly extend beyond their bounds but should lie underneath the dropdowns, maybe a layer below the primary one? not sure what a use case for that one would be 🤔). then child widgets can choose which semantic layer to live & separately hit test on.
probably overwrought though, and as compared to the current Overlay's way of doing things, it would make it more difficult to create re-usable dropdowns etc
anyway the behaviour of this widget is much closer to how i expected overlays to work than the current Overlay widget, and my impression is that people generally find Overlay fairly unintuitive to use (although i think the underlying mechanism of it is probably easier to wrap your head around than this thingy). so it would be pretty cool to upstream something like this; i'd be happy to workshop an API and hack on a PR if there's interest from any maintainers!

Well that is the nice thing actually, it's not global, you can stick DeferredPointerHandler at any level you need that works for you. So far I'm finding that is often just 1 or 2 levels up the stack. And you can have many of them, as they are really just interested in their immediate parent.
fwiw, I had it named DeferHit for most of  development, but just based the name to more closely match the existing ____Pointer widgets.

In terms of sorting, I think we could get really far with a simple DeferHit.paintOrder property or something, now you can defer painting to some ancestor, and also manually control sorting within that layer if needed. That should serve most use cases I would think.

Hi, is there any updates?

Hi there,
Are there any updates on adding a "hitSlop" (RN language) to Flutter?
Coming from React Native, this limitation seems surprising.
Yes, I created some mess with hitSlope in the past. There is a learning curve to that.
On the other hand it allows to achieve vetera elegant UI, where the border doesn't have to be huge, the icon small and the touchable area easy to click.

"So it's not like this is preventing people from writing apps" - In a world without timelines, and requirements that are fully known in advance, and every team member is a 3 year flutter veteran, this might be true, but this world doesn't exist.

Bravo for the reply.

Hi, are there any updates?

Hi, are there any updates?

You can use this library which does everything you want https://pub.dev/packages/defer_pointer

Hi, are there any updates?

You can use this library which does everything you want https://pub.dev/packages/defer_pointer

I tried this package, but Unfortunately,  it's not worked in Gridview

The reference to React Native's hitSlop (https://github.com/flutter/flutter/issues/75747#issuecomment-1253366545) makes for an interesting point of comparison, because RN hitSlop carries a crucial limitation:
By setting hitSlop, you can let an RN component receive touches that happen outside its own bounds. But no matter how big you set hitSlop, it will never receive touches that happen outside its parent's bounds. In the RN docs' terms:

The touch area never extends past the parent view bounds and the Z-index of sibling views always takes precedence if a touch hits two overlapping views.

I imagine the motivation for that limitation is exactly to mitigate the type of performance concern that @Hixie has explained in this thread: it means that when a parent component gets a potential hit, if it's outside its own bounds then it never has to pass it on to its children, regardless of what those children are trying to do with hitSlop.
In my own experience with React Native, the restriction to the parent's bounds feels kind of annoyingly arbitrary, but it doesn't pose much of an obstacle in practice. So I think hitSlop, even with that limitation, solves a lot of the use cases this issue is about.
In Flutter terms, I think the analogous design would look something like:

A HitSlop widget configures a HitSlopRenderObject.
For layout and paint, a HitSlopRenderObject defers to its child.
For hit-testing, a HitSlopRenderObject checks whether the position is in, not its actual size, but an expanded rectangle around its size, expanded by the widget's hit slop value. (Which would perhaps be an EdgeInsetsGeometry, just like Padding.padding.)

I believe that would function a lot like RN's hitSlop. It'd have the same arbitrary-feeling limitation, but would solve much the same set of use cases. And, crucially, it would cost nothing when you aren't using it, because no other widgets would have to change or gain an extra case to have to check.

@gnprice in my project we have a widget like that. It works (in some cases) but it is also error prone: Very easy for someone to wrap the widget in a Row that hugs in vertically (or Opacity, ...) and you've reduced the hit test area.

Hi, are there any updates?

You can use this library which does everything you want https://pub.dev/packages/defer_pointer

I tried this package, but Unfortunately, it's not worked in Gridview

It solved it for me, I put the DeferredPointerHandler at the highest point of the tree on the screen in question and where it needed to be touched I added the DeferPointer and the capture of the touch outside the stack went well.

@andersonmendesdev can you share some code?

Hi, are there any updates?

You can use this library which does everything you want https://pub.dev/packages/defer_pointer

@Vardiak Thank you so much! :heart:
@shahmirzali49 It worked for me on second try. You may need a Builder between DeferredPointerHandler and DeferPointer, read the documentation to understand.  That's how InheritedWidgets, such as Provider, work afaik.
The following works:
MaterialApp -> Scaffold -> DeferredPointerHandler -> LayoutBuilder -> Stack -> Transform -> DeferPointer -> Container
The following doesn't work:
MaterialApp -> Scaffold -> LayoutBuilder -> DeferredPointerHandler -> Stack -> Transform -> DeferPointer -> Container

Hi Everyone,
Incase we are still facing this issue, I had a workaround for it.

Since the Clip.none, literally stops you from clicking any area outside the Stack, I added a SizedBox as the parent of the Stack, then made the height to house all my stacked designs.

For simplicity sake, I made a modular method for each stacked section;

_profileTopSection() {
    return SizedBox(
      height: 340, // This is the MAGIC trick
      child: Stack(
        alignment: Alignment.center,
        clipBehavior: Clip.none,
        children: [
          Positioned(
            top: 0, // This pushes the _heroSection imple to the topmost section of the screen, covering the AppBar(that's intended)
            child: _heroSection(),
          ),
          Positioned(
            top: heroSectionHeight - (_profileHeight / 1.4), // This is to just get a better placement for the profile image
            child: _profileImage(),
          ),
        ],
      ),
    );
  }

Now, with the height set to it, I get to reveal the stacked items and expose them to receive the hit signature.

https://github.com/user-attachments/assets/a5b71b22-33fd-4550-9324-220b32baf4d5

authors: Hixie Shahmirzali-Huseynov Vardiak Wdestroier andersonmendesdev csells esDotDev fzyzcjy gikwegbu gnprice goderbauer ishiWaldemarSV kartik1225 marcglasberg modulovalue olof-dev rlch shrouxm spkersten


text:
_drag == null

When the exception was thrown, this was the stack:
#2      ScrollableState._handleDragDown (package:flutter/src/widgets/scrollable.dart:571:12)
#3      DragGestureRecognizer._checkDown. (package:flutter/src/gestures/monodrag.dart:401:51)
#4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24)
#5      DragGestureRecognizer._checkDown (package:flutter/src/gestures/monodrag.dart:401:7)
#6      DragGestureRecognizer.addAllowedPointer (package:flutter/src/gestures/monodrag.dart:264:7)
...
Handler: "onDown"
Recognizer: VerticalDragGestureRecognizer#6b36f
start behavior: start

@Moyout
can you provide your flutter doctor -v, your flutter run -v and a minimal reproducible code sample

Hi @Moyout
Can you please provide what was asked above?
Thank you

Without additional information, we are unfortunately not sure how to resolve this issue.
We are therefore reluctantly going to close this bug for now.
Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away!
Thanks for your contribution.
Could everyone who still has this problem please file a new issue with the exact description of what happens, logs, and the output of flutter doctor -v.
All system setups can be slightly different, so it's always better to open new issues and reference related issues.

source: gharchive/issue

authors: Moyout iapicca pedromassangocode

repo: flutter/flutter

license_type: permissive

license_source: github-api


text:
windows devicelab hosts are not performing ntp sync

win-1 and win-2 fail to perform internet time sync.
UDP-123 was opened up in the firewall, time services restarted, and multiple time servers tried. All attempts failed to successfully sync.

What are the next steps here?

We are unblocked by setting the time manually. Next steps is trying to get support by windows ops teams to determine what we can try to determine why it cannot contact the ntp servers.

@yusuf-goog is this still true?

Yes. We haven't hit it in quite a while, but the underlying issue exists.

opened t/208232709 to see if there are network firewall rules in place preventing the sync.

Looks like time.google.com works as a ntp server. Salt state to set server in: http://go/tircl/534054

Salt state change has been committed. This will resolve when states get applied to the win hosts.

authors: godofredoc yusuf-goog yusufm


text:
Flutter version constraints are not working for versions >=2.0.0

Bug description
I'm getting no error despite flutter version requirements are not satisfied.
Expected behaviour
To get error like I get when I'm on older flutter versions. For example with flutter 1.22.5 and environment restrinctions like:
environment:
  sdk: ">=2.10.0 <3.0.0"
  flutter: ">=1.0.0 <1.2.0"

I get an error running flutter pub get saying:
The current Flutter SDK version is 1.22.5.

Because [app_name] requires Flutter SDK version >=1.0.0 <1.2.0, version solving failed.
pub get failed (1; Because [app_name] requires Flutter SDK version >=1.0.0 <1.2.0, version solving failed.)

Reproduction

Create new flutter project with last flutter version from stable channel (>=2.0.0)
Make environment section of pubspec.yaml file look like this:

environment:
  sdk: ">=2.10.0 <3.0.0"
  flutter: ">=1.22.4 <1.23.0"

Run flutter pub get
Get no error despite flutter version requirements are not satisfied.

I am not sure if this is a bug or intended functionality.
Keeping this open for further insights.

I don't understand why this could be an indented functionality. Why would flutter stop showing errors if version constraints are not satisfied after 2.0 versions?

Thank you for filing this issue! However, I am going to close it as a duplicate of https://github.com/flutter/flutter/issues/95472. Please follow that issue for for more information and updates. Thanks!

authors: 0ttik christopherfujino darshankawar


text:
Need more Material Icons

Some new material icons were released (navigation/arrow_upward and navigation/arrow_downward), and I would like to use them. Can Flutter include these in their assets?
https://www.google.com/design/icons/#ic_arrow_upward

We should rev the material_design_icons package.  I don't think there are good docs for how to do that, but hopefully we can produce docs as we do this.  I'm happy to do this when I get back in January if someone doesn't do it first.  This script does most of the interesting work:
https://github.com/flutter/engine/blob/master/sky/tools/download_material_design_icons

I'm going to solve this with by fixing #994

We have these now via Icons.arrow_upward and Icons.arrow_downward

Thanks!

authors: abarth afandria


text:
gclient sync failed on mac-arm64, any plan to fix it ?

`________ running 'cipd ensure -log-level error -root /Users/zhen/source/Flutter/engine -ensure-file /var/folders/zq/l7_3q6ws7jdddd_b0r47hcc00000gn/T/tmpS9F_Vj.ensure' in '.'
Errors:
failed to resolve fuchsia/third_party/clang/mac-arm64@git_revision:7e9747b50bcb1be28d4a3236571e8050835497a6 (line 4): no such package: fuchsia/third_party/clang/mac-arm64
failed to resolve gn/gn/mac-arm64@git_revision:152c5144ceed9592c20f0c8fd55769646077569b (line 7): no such tag
failed to resolve flutter/android/ndk/mac-arm64@version:r21.0.6113669 (line 22): no such package: flutter/android/ndk/mac-arm64
failed to resolve flutter/android/sdk/build-tools/mac-arm64@version:29.0.1 (line 25): no such package: flutter/android/sdk/build-tools/mac-arm64
failed to resolve flutter/android/sdk/platform-tools/mac-arm64@version:29.0.2 (line 28): no such package: flutter/android/sdk/platform-tools/mac-arm64
failed to resolve flutter/android/sdk/tools/mac-arm64@version:26.1.1 (line 34): no such package: flutter/android/sdk/tools/mac-arm64
failed to resolve dart/dart-sdk/mac-arm64@version:2.9.0-18.0.dev (line 40): no such tag
Error: Command 'cipd ensure -log-level error -root /Users/zhen/source/Flutter/engine -ensure-file /var/folders/zq/l7_3q6ws7jdddd_b0r47hcc00000gn/T/tmpS9F_Vj.ensure' returned non-zero exit status 1
Errors:
failed to resolve fuchsia/third_party/clang/mac-arm64@git_revision:7e9747b50bcb1be28d4a3236571e8050835497a6 (line 4): no such package: fuchsia/third_party/clang/mac-arm64
failed to resolve gn/gn/mac-arm64@git_revision:152c5144ceed9592c20f0c8fd55769646077569b (line 7): no such tag
failed to resolve flutter/android/ndk/mac-arm64@version:r21.0.6113669 (line 22): no such package: flutter/android/ndk/mac-arm64
failed to resolve flutter/android/sdk/build-tools/mac-arm64@version:29.0.1 (line 25): no such package: flutter/android/sdk/build-tools/mac-arm64
failed to resolve flutter/android/sdk/platform-tools/mac-arm64@version:29.0.2 (line 28): no such package: flutter/android/sdk/platform-tools/mac-arm64
failed to resolve flutter/android/sdk/tools/mac-arm64@version:26.1.1 (line 34): no such package: flutter/android/sdk/tools/mac-arm64
failed to resolve dart/dart-sdk/mac-arm64@version:2.9.0-18.0.dev (line 40): no such tag
`

Hi @pangzhen, Thanks for filing the issue. Please share the output of flutter doctor -v along with the exact steps to reproduce the issue.
Thanks

Without additional information, we are unfortunately not sure how to resolve this issue.
We are therefore reluctantly going to close this bug for now.
Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away!
Thanks for your contribution.
Could everyone who still has this problem please file a new issue with the exact description of what happens, logs, and the output of flutter doctor -v.
All system setups can be slightly different, so it's always better to open new issues and reference related issues.

authors: TahaTesser maheshmnj pangzhen


text:
Roll Flutter Engine from ced8f1a71206 to 4c085b883d6f (2 revisions)

https://github.com/flutter/engine/compare/ced8f1a71206...4c085b883d6f
2023-09-01 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from _x3hf702RacYnw3E6... to sk7JBGzW1Jw10Wy-T... (flutter/engine#45372)
2023-09-01 leroux_bruno@yahoo.fr [Linux] Fix channel buffers control commands error handling (flutter/engine#45056)
Also rolling transitive DEPS:
fuchsia/sdk/core/mac-amd64 from _x3hf702RacY to sk7JBGzW1Jw1
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
is aware of the problem.
To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md

Commit queue failed; closing this roll.

source: gharchive/pull-request


text:
Roll Packages from e7d812cefce0 to b8b84b2304f0 (7 revisions)

https://github.com/flutter/packages/compare/e7d812cefce0...b8b84b2304f0
2023-09-01 stuartmorgan@google.com [tools,pigeon] Update tooling to handle Windows build output changes (flutter/packages#4826)
2023-08-31 amuramoto@users.noreply.github.com [google_maps_flutter] Cloud-based map styling support (flutter/packages#3682)
2023-08-31 stuartmorgan@google.com [ci] Convert version presubmit check to LUCI (flutter/packages#4822)
2023-08-31 rajveer0malviya@gmail.com [url_launcher_android] Add support for Custom Tabs (flutter/packages#4739)
2023-08-31 tarrinneal@gmail.com [webview_flutter] update pigeon to 11 (flutter/packages#4821)
2023-08-31 engine-flutter-autoroll@skia.org Roll Flutter (stable) from e1e47221e862 to ff5b5b5fa6f3 (1 revision) (flutter/packages#4823)
2023-08-31 engine-flutter-autoroll@skia.org Roll Flutter from 1fe24956ac46 to c175cf87a6a3 (30 revisions) (flutter/packages#4825)
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human
is aware of the problem.
To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md

Commit queue failed; closing this roll.


text:
Roll Packages from 2af69541a214 to fe4c86bf2091 (4 revisions)

https://github.com/flutter/packages/compare/2af69541a214...fe4c86bf2091
2023-10-28 engine-flutter-autoroll@skia.org Roll Flutter from 5907c9757e3f to a4ec6278b1a4 (18 revisions) (flutter/packages#5255)
2023-10-27 hrkadam.92@gmail.com [go_router] Fixes deep-link with no path on cold start (flutter/packages#5113)
2023-10-27 katelovett@google.com [two_dimensional_scrollables] Fix pinned row painting when one axis is reversed (flutter/packages#5187)
2023-10-27 engine-flutter-autoroll@skia.org Roll Flutter from c555599fbb4a to 5907c9757e3f (45 revisions) (flutter/packages#5252)
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human
is aware of the problem.
To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md

Commit queue failed; closing this roll.


text:
Roll Flutter Engine from a9194f0f01f4 to 18e1520b30d4 (2 revisions)

https://github.com/flutter/engine/compare/a9194f0f01f4...18e1520b30d4
2024-06-27 skia-flutter-autoroll@skia.org Roll Dart SDK from c01f907d34d8 to 8dd486ebfab4 (1 revision) (flutter/engine#53599)
2024-06-26 skia-flutter-autoroll@skia.org Roll Skia from 55ada83438cd to 001694095f1b (3 revisions) (flutter/engine#53598)
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
is aware of the problem.
To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose
To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md

Commit queue failed; closing this roll.


text:
Do not do semantics for detached objects

We were doing semantics for detached objects causing us to cache values that were outdated when the object got attached, but we failed to update them. This change:

Do not do semantics for detached objects
Throw away cached information when not doing semantics (will be outdated next time we have to do semantics)
refactor RenderObject handling of _GestureSemantics to follow the more traditional model (and avoid a bunch of calls that confuse people (aka me) who are debugging this code)

Fixes https://github.com/flutter/flutter/issues/15258, which broke a11y scrolling due to outdated cached values when semantics were turned on after the scrollable was brought onto screen.

authors: goderbauer yjbanov


text:
Make native asset integration test more robust, thereby allowing smooth auto-update of packages via flutter update-packages

Currently the bot that runs flutter update-packages makes PRs that fail due to native asset integration tests failing.
The root cause is due to incompatible versions on package:logging. The bot tries to upgrade package:logging from 1.2.0 to 1.3.0.
Here's what seems to happen:

flutter update-packages will update dev/integration_tests/link_hook/pubspec.yaml with package:logging to 1.3.0 (as it does with all other pubspec.yaml files in the flutter repository)

flutter create  --template=package_ffi will generate a template with package:logging ^1.2.0

The test in question

creates ffi template (which will use ^1.2.0)
make it depend on dev/integration_tests/link_hook (which uses =1.3.0)
changes logging dependency from the template from ^1.2.0 to =1.2.0

IMHO

flutter update-packages is doing what it's supposed to

flutter create --template=package_ffi can generate templates with versions it determines (maybe there are use cases where we want to generate templates with older versions)

The problematic part is the test:

it makes the generated template depend on link_hook and
changes template generated pubspec to use pinned dependencies

This PR makes the test package (created via template) use the pinned package versions from dev/integration_tests/link_hook (for dependencies that are common among the two).
All other dependencies that the template has on top of dev/integration_tests/link_hook it can pin as it does currently.
This will give us deterministic CI behavior (as we use flutter pined packages and remaining deps being pinned via template) It avoids changing the flutter update-packages and flutter create --template=package_ffi (as their behavior seems reasonable)
Should fix https://github.com/flutter/flutter/issues/158135

Thanks, @mraleph !


text:
Reland "Framework support for font features in text styles"

See https://github.com/flutter/flutter/issues/31691

Have the web versions of the API been added? I believe that was the reason it had to be rolled back if I remember correctly. If so, do you mind linking the change here?

@jonahwilliams committed https://github.com/flutter/engine/commit/fa2e2d9fcbf5b11e90937255c2df428fd6729f01.
Has this rolled to wherever it needs to land?

That was 7 days ago, it should be rolled in.

It does look like the engine stub_ui text.dart patch is missing docs on the  List<FontFeature> fontFeatures, parameter. We should add docs for that.

authors: GaryQian jason-simmons


text:
Roll engine ff49ca1c6e5b..ee6267d04617 (21 commits)

git@github.com:flutter/engine.git/compare/ff49ca1c6e5b...ee6267d04617
git log ff49ca1c6e5b..ee6267d04617 --no-merges --oneline
2019-08-10 skia-flutter-autoroll@skia.org Roll src/third_party/skia fe19203eb7d7..89e43889afd9 (1 commits) (flutter/engine#10824)
2019-08-10 skia-flutter-autoroll@skia.org Roll fuchsia/sdk/core/linux-amd64 from HsuAH... to bvUCO... (flutter/engine#10822)
2019-08-10 bkonyi@google.com Roll src/third_party/dart ffefa124a7..e29d6d0ecb (4 commits)
2019-08-10 skia-flutter-autoroll@skia.org Roll src/third_party/skia af89d3972e0b..fe19203eb7d7 (5 commits) (flutter/engine#10819)
2019-08-10 bkonyi@google.com Roll src/third_party/dart 15a3bf82cb..ffefa124a7 (11 commits)
2019-08-09 chris@bracken.jp Roll Dart SDK 78ce916d82..15a3bf82cb (flutter/engine#10810)
2019-08-09 skia-flutter-autoroll@skia.org Roll src/third_party/skia b7b0b3ad538c..af89d3972e0b (7 commits) (flutter/engine#10812)
2019-08-09 jonahwilliams@google.com Revert "Remove flutter_kernel_sdk dart script (#10808)" (flutter/engine#10811)
2019-08-09 iska.kaushik@gmail.com [dart:zircon] Porting Cache re-usable handle wait objects (flutter/engine#10809)
2019-08-09 jonahwilliams@google.com Remove flutter_kernel_sdk dart script (flutter/engine#10808)
2019-08-09 cfontas@google.com change add part to add child (flutter/engine#10787)
2019-08-09 yjbanov@google.com rename stub_ui to web_ui (flutter/engine#10776)
2019-08-09 kpozin@google.com [fuchsia] Migrate from custom FuchsiaFontManager to SkFontMgr_fuchsia (flutter/engine#10700)
2019-08-09 skia-flutter-autoroll@skia.org Roll src/third_party/skia 26cedb4c603b..b7b0b3ad538c (11 commits) (flutter/engine#10807)
2019-08-09 egarciad@google.com Rename flutter_java.jar and flutter_engine.jar so they match the Maven comvention (flutter/engine#10797)
2019-08-09 skia-flutter-autoroll@skia.org Roll fuchsia/sdk/core/linux-amd64 from 9xVXx... to HsuAH... (flutter/engine#10806)
2019-08-09 bkonyi@google.com Roll src/third_party/dart 3d9a356f6e..78ce916d82 (7 commits)
2019-08-09 skia-flutter-autoroll@skia.org Roll src/third_party/skia b2151310068b..26cedb4c603b (1 commits) (flutter/engine#10804)
2019-08-09 skia-flutter-autoroll@skia.org Roll src/third_party/skia 059bf776c184..b2151310068b (3 commits) (flutter/engine#10803)
2019-08-09 bkonyi@google.com Roll src/third_party/dart f29f41f1a5..3d9a356f6e (65 commits)
2019-08-09 skia-flutter-autoroll@skia.org Roll src/third_party/skia 4d557e3df433..059bf776c184 (1 commits) (flutter/engine#10801)
The AutoRoll server is located here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md
If the roll is causing failures, please contact the current sheriff (jimgraham@google.com), and stop
the roller if necessary.

Trybots failed. These were the failed builds: https://cirrus-ci.com/task/5842359068131328 , https://cirrus-ci.com/task/6123834044841984

Commit queue failed; closing this roll.