So after many tries to solve this answer I've realized the following and came up with a solution that might help you.
a textField
in a listview that has maxlines: null
will auto-scroll the listView with no issues but for some reason, flutter_quill has some issues
now my work around this is as follows ( full code will be at the bottom ):
- first we define a couple of variables in the state class of the widget that has this form
final quill.QuillController quillController = quill.QuillController.basic();
final FocusNode editorFocusNode = FocusNode();
bool isToolBarVisible = true;
you already have the controller defined but for the other 2 attributes, you will need them to show/hide the toolbar based on the focused node.
- instead of using a simple ListView, we use a customScrollView which makes it possible for us to create a more complex listview, it uses slivers ( a sliver is a scrollable widget, you can learn more about it )
Form(
child: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
toolbarHeight: isToolBarVisible ? 50 : 0,
title:
Visibility(visible: isToolBarVisible, child: getToolBar()),
),
SliverToBoxAdapter(
child: Column(
children: getTextFields(),
),
),
SliverFillRemaining(
hasScrollBody: true,
child: getEditor(),
),
],
),
using the sliver app bar we can pin the quill toolbar, using the sliver to box adapter we can add the normal text fields, and then to expand the quill editor we use sliverFillRemaining.
here are the sub-functions:
Widget getToolBar() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: quill.QuillToolbar.basic(
controller: quillController,
showUnderLineButton: false,
showStrikeThrough: false,
showColorButton: false,
showBackgroundColorButton: false,
showListCheck: false,
showIndent: false,
),
);
}
List<Widget> getTextFields() {
return [
Text("From: [email protected]"),
SizedBox(height: 8),
TextField(
decoration: InputDecoration(labelText: "To"),
),
TextField(
decoration: InputDecoration(labelText: "Cc"),
),
TextField(
decoration: InputDecoration(labelText: "Bcc"),
),
];
}
Widget getEditor() {
return QuillEditor(
controller: quillController,
scrollable: true,
scrollController: ScrollController(),
focusNode: editorFocusNode,
padding: EdgeInsets.all(5),
autoFocus: true,
readOnly: false,
expands: false,
placeholder: "compose_email",
);
}
replace the normal textFields with your chipInputField
finally here is the full code:
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;
import 'package:flutter_quill/widgets/editor.dart';
class FlutterQuillForm extends StatefulWidget {
@override
_FlutterQuillFormState createState() => _FlutterQuillFormState();
}
class _FlutterQuillFormState extends State<FlutterQuillForm> {
final quill.QuillController quillController = quill.QuillController.basic();
final FocusNode editorFocusNode = FocusNode();
bool isToolBarVisible = true;
@override
void initState() {
editorFocusNode.addListener(() {
setState(() {
isToolBarVisible = editorFocusNode.hasFocus;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Reply form"),
actions: [
IconButton(
onPressed: () {},
icon: Icon(Icons.send),
tooltip: "Send",
)
],
),
body: SafeArea(
child: Form(
child: CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
toolbarHeight: isToolBarVisible ? 50 : 0,
title:
Visibility(visible: isToolBarVisible, child: getToolBar()),
),
SliverToBoxAdapter(
child: Column(
children: getTextFields(),
),
),
SliverFillRemaining(
hasScrollBody: true,
child: getEditor(),
),
],
),
),
),
);
}
Widget getToolBar() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: quill.QuillToolbar.basic(
controller: quillController,
showUnderLineButton: false,
showStrikeThrough: false,
showColorButton: false,
showBackgroundColorButton: false,
showListCheck: false,
showIndent: false,
),
);
}
List<Widget> getTextFields() {
return [
Text("From: [email protected]"),
SizedBox(height: 8),
TextField(
decoration: InputDecoration(labelText: "To"),
),
TextField(
decoration: InputDecoration(labelText: "Cc"),
),
TextField(
decoration: InputDecoration(labelText: "Bcc"),
),
];
}
Widget getEditor() {
return QuillEditor(
controller: quillController,
scrollable: true,
scrollController: ScrollController(),
focusNode: editorFocusNode,
padding: EdgeInsets.all(5),
autoFocus: true,
readOnly: false,
expands: false,
placeholder: "compose_email",
);
}
@override
void dispose() {
super.dispose();
quillController.dispose();
}
}
in the focus node listener, we can set the state of the toolbar to be visible or invisible and don't forget to dispose the controllers and the focus node.
screenshots: