You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调整TypeAheadFormField中复制粘贴工具提示的对齐方式

Fixing Copy/Paste Tooltip Alignment Issue in TypeAheadFormField with Multiline Text

Hey there! I’ve dealt with this exact annoying tooltip alignment bug in TypeAheadFormField when working with multiline text and interactive selection before. Let’s walk through why it happens and how to fix it.

Why This Happens

The core problem is that the TypeAhead widget’s overlay positioning logic doesn’t account for external scrollable parents (like your SingleChildScrollView) or the dynamic height of a multiline TextField. When you select text, the tooltip calculates its position based on the original widget bounds instead of the visible viewport after scrolling, which makes it jump to the top of the screen.


Solution 1: Custom Text Selection Controls to Adjust Tooltip Position

We can create a custom TextSelectionControls that recalculates the tooltip position relative to the selected text, rather than relying on the default widget bounds. This ensures the tooltip stays anchored to your selected text no matter where it is in the scrollable area.

First, define the custom controls:

class CustomTextSelectionControls extends MaterialTextSelectionControls {
  @override
  Widget buildToolbar(
    BuildContext context,
    Rect globalEditableRegion,
    double textLineHeight,
    Offset selectionMidpoint,
    List<TextSelectionPoint> endpoints,
    TextSelectionDelegate delegate,
    ClipboardStatusNotifier? clipboardStatus,
    Offset? lastSecondaryTapDownPosition,
  ) {
    // Adjust the tooltip offset to sit just below the selected text
    final Offset adjustedOffset = Offset(
      selectionMidpoint.dx,
      selectionMidpoint.dy + textLineHeight,
    );

    return super.buildToolbar(
      context,
      globalEditableRegion,
      textLineHeight,
      adjustedOffset,
      endpoints,
      delegate,
      clipboardStatus,
      lastSecondaryTapDownPosition,
    );
  }
}

Then add it to your TextFieldConfiguration:

textFieldConfiguration: TextFieldConfiguration(
  enableInteractiveSelection: true,
  controller: txtController,
  focusNode: txtFocus,
  textInputAction: TextInputAction.newline,
  keyboardType: TextInputType.multiline,
  maxLines: null,
  // Attach our custom selection controls
  selectionControls: CustomTextSelectionControls(),
  decoration: InputDecoration.collapsed(
    hintText: "Type a message",
  ),
),

Solution 2: Simplify the Widget Tree

Your SingleChildScrollView is redundant here because the multiline TextField already supports internal scrolling when constrained to a max height. Removing it eliminates the position mismatch that causes the tooltip to jump.

Here’s the revised widget tree:

Expanded(
  child: Container(
    child: ConstrainedBox(
      constraints: BoxConstraints(
        minHeight: 25,
        maxHeight: 100.0,
      ),
      // Remove the external SingleChildScrollView
      child: Padding(
        padding: const EdgeInsets.only(left: 5, bottom: 3),
        child: TypeAheadFormField(
          direction: AxisDirection.up,
          textFieldConfiguration: TextFieldConfiguration(
            enableInteractiveSelection: true,
            controller: txtController,
            focusNode: txtFocus,
            textInputAction: TextInputAction.newline,
            keyboardType: TextInputType.multiline,
            maxLines: null,
            decoration: InputDecoration.collapsed(
              hintText: "Type a message",
            ),
          ),
          validator: (value) {
            if (value.isEmpty) {
              return 'Please enter the message';
            }
            return null;
          },
          // Don't forget to add required TypeAhead callbacks
          suggestionsCallback: (pattern) async {
            // Replace with your actual suggestions logic
            return [];
          },
          itemBuilder: (context, suggestion) {
            return ListTile(title: Text(suggestion.toString()));
          },
          onSuggestionSelected: (suggestion) {
            txtController.text = suggestion.toString();
          },
        ),
      ),
    ),
  ),
)

Which Solution Should You Use?

  • Use Solution 1 if you absolutely need the external SingleChildScrollView (for example, if you have other widgets inside it alongside the TextField).
  • Use Solution 2 for a cleaner, more performant fix—it removes unnecessary widget nesting and leverages the TextField’s built-in scrolling capabilities.

Either approach should resolve the tooltip alignment issue and keep your copy/paste controls anchored to the selected text.

内容的提问来源于stack exchange,提问作者VigneshK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:32:37