I would like to put my QuillEditor
inside my form and not on a dedicated page of my app.
I've tried with a Column
inside a SingleChildScrollView
and with a ListView
widget, but the result is the same:
Here's some code:
return Scaffold(
appBar: AppBar(
title: Text("Reply form"),
actions: [
IconButton(
onPressed: () {},
icon: Icon(Icons.send),
tooltip: "Send",
)
],
),
body: SafeArea(
child: Form(
child: ListView(
children: [
Text("From: [email protected]"),
SizedBox(height: 8),
chipInputField(
label: "To",
onChanged: (List<Object?> o) {},
initialValue: ["[email protected]"],
),
chipInputField(
label: "Cc",
onChanged: (List<Object?> o) {},
initialValue: ["[email protected]"],
),
chipInputField(
label: "Bcc",
onChanged: (List<Object?> o) {},
initialValue: ["[email protected]"],
),
QuillEditor(
controller: quillController,
scrollable: true,
scrollController: ScrollController(),
focusNode: FocusNode(),
padding: EdgeInsets.all(5),
autoFocus: true,
readOnly: false,
expands: false,
placeholder: "compose_email",
),
QuillToolbar.basic(
controller: quillController,
showUnderLineButton: false,
showStrikeThrough: false,
showColorButton: false,
showBackgroundColorButton: false,
showListCheck: false,
showIndent: false,
),
],
),
),
),
);
First issue: the compose email part is not expanded inside the application page
Second issue: as long as I write some text, the widget is not scrolling
Edit: I'm using Flutter 2.2.3 and flutter_quill: 1.3.3
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 ):
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.
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: