I want to Create an TextField
at the bottom of the page like message app.
There is also a IconButton
, which adds the entered text into ListView
if TextField
is not empty. If it is empty then it will show error in SnackBar
.
The Problem is the SnackBar
stacks on top of TextField
. But I want it to be either top or bottom of TextField
.
import 'package:flutter/material.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
final _textList = <String>[];
TextEditingController _textController;
bool _addText(context, String text) {
print(text);
if (text?.isNotEmpty == true) {
setState(() {
_textList.add(text);
});
return true;
} else {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text("Invalid Text Entered"),
behavior: SnackBarBehavior.fixed,
),
);
return false;
}
}
@override
void initState() {
_textController = TextEditingController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: ListView.separated(
itemCount: _textList.length,
separatorBuilder: (_, __) => Divider(height: 1.0),
itemBuilder: (context, index) => ListTile(
title: Text("${_textList[index]}"),
),
),
),
_buildBottom(),
],
),
),
);
}
Widget _buildBottom() {
return Material(
elevation: 5.0,
color: Colors.blue[100],
child: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Enter Text",
contentPadding: EdgeInsets.symmetric(horizontal: 10.0),
border: InputBorder.none,
),
),
),
Builder(
builder: (context) => IconButton(
icon: Icon(Icons.add),
onPressed: () {
final success = _addText(context, _textController.text);
if (success) _textController.clear();
},
),
),
],
),
);
}
}
This is my code in DartPad
Solution 1: Arhaam Patvi
Perhaps using Flushbar
might help with your problem. There are many properties that you can change, such as flushbarPosition
.
It might not solve your problem exactly how you would expect it to but it can make the Flushbar appear from the top instead of the bottom and that's one way around your problem
Flushbar
: https://pub.dev/packages/flushbar
Solution 2: Jay Gadariya
try this,
import 'package:flutter/material.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
final _textList = <String>[];
TextEditingController _textController;
bool isVisible = false;
bool _addText(context, String text) {
print(text);
if (text?.isNotEmpty == true) {
setState(() {
_textList.add(text);
});
return true;
} else {
Scaffold.of(context).showSnackBar(
new SnackBar(
content: Text("Invalid Text Entered"),
behavior: SnackBarBehavior.fixed,
duration: Duration(seconds: 3),
onVisible: (() {
setState(() {
isVisible = true;
});
Future.delayed(Duration(seconds: 3)).then((_) => setState(() {
isVisible = false;
}));
}),
),
);
return false;
}
}
@override
void initState() {
_textController = TextEditingController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo"),
),
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: ListView.separated(
itemCount: _textList.length,
separatorBuilder: (_, __) => Divider(height: 1.0),
itemBuilder: (context, index) => ListTile(
title: Text("${_textList[index]}"),
),
),
),
AnimatedContainer(
margin: EdgeInsets.only(bottom: isVisible ? 50 : 0),
child: _buildBottom(),
duration: Duration(milliseconds: 100),
),
],
),
),
);
}
Widget _buildBottom() {
return Material(
elevation: 5.0,
color: Colors.blue[100],
child: Row(
children: <Widget>[
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Enter Text",
contentPadding: EdgeInsets.symmetric(horizontal: 10.0),
border: InputBorder.none,
),
),
),
Builder(
builder: (context) => IconButton(
icon: Icon(Icons.add),
onPressed: () {
final success = _addText(context, _textController.text);
if (success) _textController.clear();
},
),
),
],
),
);
}
}
Solution 3: Stefano Saitta
I think the best thing you can do here is to change the behaviour
to floating
SnackBar(
behavior: SnackBarBehavior.floating,
...