flutter-quill icon indicating copy to clipboard operation
flutter-quill copied to clipboard

Issue with QuillEditor Scrolling Inside SingleChildScrollView

Open koraxis opened this issue 1 year ago • 17 comments

Is there an existing issue for this?

The question

Issue Description

I'm encountering a scrolling issue with QuillEditor when it's placed inside a SingleChildScrollView and wrapped within a Column that also contains other widgets. Specifically, the editor does not automatically scroll to follow the cursor when it moves behind the keyboard.

Steps to Reproduce

  1. Place QuillEditor inside a SingleChildScrollView.
  2. Wrap QuillEditor and another widget (e.g., a TextField or Text) inside a Column.
  3. When focusing on the QuillEditor and typing enough content to move the cursor below the keyboard, the editor does not automatically scroll to keep the cursor visible.

Example Code

class SamplePage extends StatelessWidget {
  SamplePage({super.key});

  final QuillController bodyQuillController = QuillController.basic();
  final ScrollController _scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            color: Colors.red,
            height: 200,
            child: const Center(child: Text('HEADER')),
          ),
          QuillProvider(
            configurations: QuillConfigurations(
              controller: bodyQuillController,
            ),
            child: QuillEditor(
              scrollController: _scrollController,
              focusNode:  FocusNode(),
              configurations: const QuillEditorConfigurations(
                scrollable: false,
                autoFocus: true,
                readOnly: false,
                expands: false,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Expected Behavior

I expect the QuillEditor to automatically scroll so that the cursor always remains visible when typing, especially when it moves behind the on-screen keyboard.

Actual Behavior

The editor does not scroll, and as a result, the cursor goes behind the keyboard, making it difficult to see what is being typed.

Flutter Environment

  • Flutter version: 3.16.3
  • flutter_quill version: 8.6.1

Additional Context

  • This issue is critical for maintaining a good user experience, as text visibility is a fundamental requirement for text editors.
  • I've tried various workarounds, including custom scroll controllers and focus node listeners, but haven't found a satisfactory solution.

Any insights or suggestions for resolving this issue would be greatly appreciated. Thank you!

koraxis avatar Dec 13 '23 10:12 koraxis

Hello there, on behalf the Flutter Quill Team I would like to thank you for opening your first issue. Your inputs and insights are valuable in shaping a stable and reliable version for all our users. Thank you for being part of the open-source community!

singerdmx avatar Dec 13 '23 10:12 singerdmx

Hi, thank you for the report. You should use scrollable property instead of the quill editor, or QuillSingleChildScrollView

EchoEllet avatar Dec 13 '23 11:12 EchoEllet

Hi, thank you for the report. You should use scrollable property instead of the quill editor, or QuillSingleChildScrollView

Hi @freshtechtips, thanks for the response.

I cannot use your first suggestion of just setting the scrollable to true and removing the SingleChildScrollView because it doesn't work with my requirements since I need the whole page to be scrollable. I want to add more widgets below and above the QuillEditor.

About your second suggestion. QuillSingleChildScrollView is not publicly available (not exported through barrel files). If I directly use it from the lib/src folder, ignoring the warnings, the editor scrolls down to the cursor location, but the rest of the widgets inside the column are not scrollable anymore.

class SamplePage extends StatelessWidget {
  SamplePage({super.key});

  final QuillController bodyQuillController = QuillController.basic();
  final ScrollController _scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return QuillSingleChildScrollView(
      controller: _scrollController,
      viewportBuilder: (BuildContext context, ViewportOffset position) {
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              color: Colors.red,
              height: 200,
              child: const Center(child: Text('HEADER')),
            ),
            QuillEditor.basic(
              scrollController: _scrollController,
              focusNode: FocusNode(),
              configurations: QuillEditorConfigurations(
                scrollable: false,
                autoFocus: true,
                readOnly: false,
                expands: false,
                controller: bodyQuillController,
              ),
            ),
          ],
        );
      },
    );
  }
}

koraxis avatar Dec 13 '23 13:12 koraxis

About your second suggestion. QuillSingleChildScrollView is not publicly available (not exported through barrel files). If I directly use it from the lib/src folder, ignoring the warnings, the editor scrolls down to the cursor location, but the rest of the widgets inside the column are not scrollable anymore.

Correct, we already exported it in the next pre-release

EchoEllet avatar Dec 13 '23 13:12 EchoEllet

Did you tried to use Expanded widget inside the children of the Column?

I have fixed size widgets in the column, so that doesn't have any effect.

koraxis avatar Dec 15 '23 08:12 koraxis

I even faced same issue. I tried some 10-12 solutions , and none of them worked . It would have been better if Quill Editor had some scrollPadding like textfield. Because whatever I tried nothing got effect on this editor . It always remain behind keyboard

santhoshPE avatar Dec 15 '23 18:12 santhoshPE

I'm facing same issue. Quill Editor always remain behind keyboard.

thanglq1 avatar Dec 17 '23 14:12 thanglq1

Hi, is there any solution to make it work around?

thanglq1 avatar Dec 23 '23 14:12 thanglq1

Same issue here, if text is long is not visible :(

Mmisiek avatar Dec 31 '23 21:12 Mmisiek

Duplicate of https://github.com/singerdmx/flutter-quill/issues/1580

Mmisiek avatar Jan 01 '24 00:01 Mmisiek

Same issue

debovitch avatar Jan 03 '24 15:01 debovitch

Is it be possible to get a stream of the cursors' position relative to the viewport?

If I had this, I could use the scroll controller of the SingleChildScrollView to keep the cursor on screen.

orourkedd avatar Apr 03 '24 22:04 orourkedd

Same issue

davebound avatar Apr 16 '24 16:04 davebound

any update?

LOCKEDFILE avatar May 21 '24 06:05 LOCKEDFILE

Same issue here.

changguangyu avatar Jun 26 '24 05:06 changguangyu

Same issue

jan10 avatar Jul 11 '24 12:07 jan10

https://github.com/singerdmx/flutter-quill/issues/1599#issuecomment-1853754167, This comment was helpful to me. I encountered an issue where the scroll position(rendering issue) was not being reflected immediately when scrolling, so I forked it and made some minor modifications. I'm not sure if this fix is correct, but it's working for now.

how to use:

  flutter_quill:
    git: https://github.com/LOCKEDFILE/flutter-quill.git
return Scaffold(
  appBar: AppBar(title: const Text('appbar')),
  body: Column(
    children: [
      Expanded(
        child: Scrollbar(
          controller: scrollController,
          notificationPredicate: (notification) {
            if (!canScroll) {
              canScroll = true;
              setState(() {});
            }
            return notification.depth == 0;
          },
          child: QuillSingleChildScrollView(
            controller: _scrollController,
            viewportBuilder: (BuildContext context, ViewportOffset position) {
              return Padding(
                padding: EdgeInsets.only(
                    bottom: MediaQuery.of(context).viewInsets.bottom),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    header1Widget(),
                    header2Widget(),
                    QuillEditor.basic(
                      scrollController: _scrollController,
                      focusNode: _focusNode,
                      configurations: QuillEditorConfigurations(
                        padding: const EdgeInsets.all(16),
                        scrollable: false,
                        autoFocus: true,
                        expands: false,
                        controller: bodyQuillController,
                      ),
                    ),
                    footerWidget(),
                  ],
                ),
              );
            },
          ),
        ),
      ),
      stickyWidget(),
    ],
  ),
);

https://github.com/user-attachments/assets/fa5280d2-3087-42a0-ac09-6398899dd10e

LOCKEDFILE avatar Jul 18 '24 03:07 LOCKEDFILE