2

I have a CustomScrollView with a SliverAppBar that hides on scroll.

On the app bar is a search button that, when pressed, puts a TextField into the app bar.

When the field gets focus, it causes the scroll view to scroll all the way to the top, and the app bar gets stuck up in the "unsafe" area:

scroll on focus issue

The Scaffold docs mention that when the keyboard is shown the scaffold's insets change and the scaffold is rebuilt, causing the "focused widget will be scrolled into view if it's within a scrollable container".

This seems like the behavior I don't want. I looked but couldn't understand the mechanism or how to suppress it. Is doing so possible?

The source code for the view in the image is here.

Also I note that this problem didn't happen in my previous implementation with non-sliver, standard widgets. I suspect this is because the app bar was not in a scrollable view, whereas SliverAppBar is inside the CustomScrollView so that it can interact with the main body.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
Aaron
  • 915
  • 9
  • 21
  • Not sure if this will solve the problem but try to make App bar with `floating: true, pinned: true, snap: true` . [Doc Reference](https://api.flutter.dev/flutter/material/SliverAppBar-class.html) – dev-aentgs Jun 25 '20 at 14:52
  • I don’t want it pinned, so even if that addressed the scrolling and/or safe area issues, it still wouldn’t solve my problem. – Aaron Jun 25 '20 at 15:03
  • ok. just asking, setting `pinned: false,` again gives scrolling/SafeArea issue? – dev-aentgs Jun 25 '20 at 15:52
  • 1
    The gif above shows the `pinned: false` case. The `pinned: true` case keeps the app bar locked in the right place, but the content underneath still scrolls, and it scrolls to a slightly wrong offset (overlapped a bit by bar). – Aaron Jun 25 '20 at 23:56

2 Answers2

2

Edit: This issue was fixed by this PR which appears to have first landed in Flutter 1.22.0.

It took some sleuthing, but I eventually found the mechanism for this behavior.

TextField wraps EditableText. When the latter gains focus, it will invoke _showCaretOnScreen, which includes a call to renderEditable.showOnScreen. This bubbles up and eventually causes the scrolling behavior.

We can force _showCaretOnScreen to return early here if we supply to the TextField a hacked ScrollController that always returns false from hasClients:

class _HackScrollController extends ScrollController {
  // Causes early return from EditableText._showCaretOnScreen, preventing focus
  // gain from making the CustomScrollView jump to the top.
  @override
  bool get hasClients => false;
}

The behavior does not seem intentional, so I reported it as bug #60422.

Caveats

This workaround may not be very stable.

I don't know what adverse effects the hasClients override might have.

The docs for TextField say that the scrollController is used "when vertically scrolling the input". In this use case we don't want vertical scrolling anyway, so the workaround might not cause any problems. In my brief testing it didn't seem to cause problems with horizontal (overflow) scrolling.

Aaron
  • 915
  • 9
  • 21
0

Just like the documentation mentions try and use resizeToAvoidBottomInset parameter to false (defaults to true) in the scaffold widget https://api.flutter.dev/flutter/material/Scaffold/resizeToAvoidBottomInset.html

Also I would recommend creating ValueListenableBuilder after the scaffold (as the first widget in the body) to avoid rebuilding the whole scaffold and just the body widget

EdwynZN
  • 4,895
  • 2
  • 12
  • 15
  • `resizeToAvoidBottomInset: false` doesn't affect this. The `ValueListenableBuilder` is outside the scaffold because in the previous implementation I needed to use the result value when building the scaffold. But yes, it could be moved inside now. – Aaron Jun 25 '20 at 14:39
  • What about using resizeToAvoidBottomInset and wrapping the widget with a SafeArea? – EdwynZN Jun 25 '20 at 14:45
  • `resizeToAvoidBottomInset` has no effect on this at all. `SafeArea` around the app bar a) makes it look weird, since the app bar *should* be in the unsafe area a little bit, and b) and doesn't affect the scroll-to-top behavior. – Aaron Jun 25 '20 at 15:17
  • are you using SliverSafeArea for the SliverAppBar? or just SafeArea over the Scaffold? – EdwynZN Jun 25 '20 at 17:02
  • It doesn't matter because both are wrong: both the scaffold and the app bar *need* to be in the unsafe area. And that still doesn't address the scrolling behavior. – Aaron Jun 25 '20 at 23:50