Skip to content

Constrain RawAutocomplete options by soft keyboard#163868

Closed
victorsanni wants to merge 13 commits intoflutter:masterfrom
victorsanni:autocomplete-soft-keyboard
Closed

Constrain RawAutocomplete options by soft keyboard#163868
victorsanni wants to merge 13 commits intoflutter:masterfrom
victorsanni:autocomplete-soft-keyboard

Conversation

@victorsanni
Copy link
Contributor

@victorsanni victorsanni commented Feb 21, 2025

Fixes Autocomplete options overlay should automatically moves up when soft keyboard is visible

Before

before.soft.keyboard.mov

After

Screen.Recording.2025-02-28.at.4.04.29.PM.mov
Sample code
import "package:flutter/material.dart";

void main() => runApp(const AutocompleteExampleApp());

/// Flutter code sample for [RawAutocomplete].

class AutocompleteExampleApp extends StatelessWidget {
  const AutocompleteExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text("RawAutocomplete Basic"),
        ),
        body: const CustomScrollView(
          slivers: [
            SliverPadding(padding: EdgeInsets.symmetric(vertical: 300)),
            SliverToBoxAdapter(child: AutocompleteBasicExample()),
            SliverPadding(padding: EdgeInsets.symmetric(vertical: 700)),
          ],
        ),
      ),
    );
  }
}

class AutocompleteBasicExample extends StatelessWidget {
  const AutocompleteBasicExample({super.key});

  static const List<String> _options = <String>[
    "aardvark",
    "bobcat",
    "chameleon",
    "chameleon",
  ];

  @override
  Widget build(BuildContext context) {
    return RawAutocomplete<String>(
      optionsBuilder: (TextEditingValue textEditingValue) {
        return _options.where((String option) {
          return option.contains(textEditingValue.text.toLowerCase());
        });
      },
      fieldViewBuilder: (
        BuildContext context,
        TextEditingController textEditingController,
        FocusNode focusNode,
        VoidCallback onFieldSubmitted,
      ) {
        return TextFormField(
          controller: textEditingController,
          focusNode: focusNode,
          onFieldSubmitted: (String value) {
            onFieldSubmitted();
          },
        );
      },
      optionsViewBuilder: (
        BuildContext context,
        AutocompleteOnSelected<String> onSelected,
        Iterable<String> options,
      ) {
        return const Column(
          children: <Widget>[Expanded(child: Placeholder())],
        );
      },
    );
  }
}

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added the framework flutter/packages/flutter repository. See also f: labels. label Feb 21, 2025
@flutter-dashboard
Copy link

Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change).

If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #163868 at sha 2333722

@flutter-dashboard flutter-dashboard bot added the will affect goldens Changes to golden files label Feb 21, 2025
@LongCatIsLooong
Copy link
Contributor

Instead of making the options view shorter, can you move the autocomplete widget up? I believe you can override https://main-api.flutter.dev/flutter/rendering/RenderObject/showOnScreen.html to achieve that.

fieldOffset = nextFieldOffset;
});
}
bottomInset = MediaQuery.viewInsetsOf(rootOverlayContext).bottom;
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong Feb 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So viewInsets is accounted for in the calculation, but not the viewPadding? Do you think we should be using padding here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, why bottom only if the insets may have positive top value, for example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About both questions, I'm not sure. Currently the options view just takes up the space on the entire screen, ignoring safearea, view padding and all that. I'm not sure if this is intentional or not. @justinmc what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't seem to have been addressed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, why bottom only if the insets may have positive top value, for example?

The documentation for MediaQuery.viewInsets says only .bottom is relevant because of the system keyboard? Unless I am missing something.

removeCompositionCallback = widget.optionsLayerLink.leader?.addCompositionCallback(
_onLeaderComposition,
);
rootOverlayContext = Overlay.of(context).context;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not necessarily target the root overlay if there are nested Overlays, as the variable name would indicate it seems?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true. The reason for this is to grab the context before the Scaffold applies Mediaquery.removePadding (when Scaffold.resizeToAvoidBottomInset is set to true), and this would no longer work if there is an Overlay between RawAutocomplete and Scaffold in the widget tree. But I don't know any better alternatives, do you have any ideas?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should target the root overlay now after the suggestion in #163868 (comment)

fieldOffset = nextFieldOffset;
});
}
bottomInset = MediaQuery.viewInsetsOf(rootOverlayContext).bottom;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't seem to have been addressed?

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some questions, but I'll defer to @LongCatIsLooong

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renewing my LGTM, thanks for the changes 👍

// The padding and view insets might have already been removed. To get the
// correct padding and view insets, use the build context of the root
// overlay.
final EdgeInsets padding = MediaQuery.paddingOf(rootOverlayContext);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The padding and view insets might have already been removed.

Then this probably should happen in the OverlayPortal implementation, so the overlayChild sees the correct MediaQuery?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in that case how would the CustomSingleChildLayout get the padding values to apply to the child constraints? Maybe the MediaQuery.removePadding should happen in the OverlayPortal implementation over the entire overlaychild, but the padding values should still be retrieved here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can still get it from MediaQueryData?

VoidCallback? removeCompositionCallback;
late BuildContext rootOverlayContext;
double bottomPadding = 0.0;
double topPadding = 0.0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, why bottom / top paddings specifically? Shouldn't we keep track of the EdgetInsets to avoid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add left and right as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just keep the EdgeInsets? or better yet it doesn't have to be kept in instance variables if you update the MediaQuery of the overlayChild

@victorsanni victorsanni marked this pull request as draft April 16, 2025 22:50
@victorsanni
Copy link
Contributor Author

Hi @LongCatIsLooong. Will #170818 also unblock this PR?

@LongCatIsLooong
Copy link
Contributor

Hi @LongCatIsLooong. Will #170818 also unblock this PR?

Yeah I think so

@Piinks
Copy link
Contributor

Piinks commented Aug 18, 2025

Hi @LongCatIsLooong. Will #170818 also unblock this PR?

Yeah I think so

Normally I would say greetings from stale PR triage, but now I see why you asked about #170818, I did not realize this was blocked on that. I'll see if I can turn that around ASAP. 👍

@Piinks
Copy link
Contributor

Piinks commented Jan 12, 2026

I am going to suggest closing this for now. I am working with a contributor on the blocking issue, after which we can reopen this - although it may be easier to resolve the conflicts and update for the large lint overhaul in a fresh PR. :)

@Piinks Piinks closed this Jan 12, 2026
@victorsanni
Copy link
Contributor Author

Reopening as blocker has been resolved.

@victorsanni victorsanni reopened this Feb 4, 2026
@fluttergithubbot
Copy link
Contributor

An existing Git SHA, f29d11d2283073b25d37e205312c537e3743813f, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

@victorsanni
Copy link
Contributor Author

Easier to close and open a new PR because of the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

framework flutter/packages/flutter repository. See also f: labels. will affect goldens Changes to golden files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Autocomplete options overlay should automatically moves up when soft keyboard is visible

5 participants