Using builTextField() method to create textField, passing different controller.
TextEditingController phoneController;
TextEditingController otpController;
builTextField(phoneController),
builTextField(otpController),
hintText is populated using phoneController.text and otpController.text for respective textFields.
Similarly,
using buildRaisedButton() method to create Button, passing differetnt callback.
buildRaisedButton('Register', registrationCallback),
buildRaisedButton('Verify', verifyOTPCallback),
buildRaisedButton('Reset',resetCallback),
on button click 'Reset', want to clear the hitText of both the textfields
resetCallback(){
print('cleared ....');
setState(() {
phoneController.clear();
otpController.clear();
});
}
It looks like controller.clear is resetting the conroller.text value to empty(''), but as the value for hintText is chosen to be conroller.text, should also get updated in screen to 'empty'. but unfortunately somehow its not reflecting in UI, eventhough wrapped the code inside setState()
buildTextField()
Widget buildTextField(TextEditingController controller, ) {
return Container(
height: 40.0,
width: 200.0,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(32),
),
child: TextField(
keyboardType: TextInputType.number,
style: kPhoneAuthTextFields,
decoration: InputDecoration(
hintStyle: kPhoneAuthTextFields,
hintText:controller.text,
suffixIcon: Icon(Icons.phone_android,size: 20,color: Colors.white,),
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 5.0, left: 30.0),
),
onChanged: (value) {
controller.text = value;
},
),
);
}
buildRaisedButton()
Widget buildRaisedButton(String label, Function callback){
return Container(
height: 40.0,
width: 100.0,
child: RaisedButton(
child:Text(
label,
style: kPhoneLoginTextStyle,
),
color: Colors.blue,
//padding: EdgeInsets.all(8.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40.0)),
onPressed: callback,
),
);
}
any help, appreciated... Thanks in Advance...
You can copy paste run full code below
In your case, you can provide UniqueKey() in buildTextField
code snippet
Widget buildTextField(TextEditingController controller,) {
return Container(
key: UniqueKey(),
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
TextEditingController phoneController = TextEditingController();
TextEditingController otpController = TextEditingController();
void _incrementCounter() {
setState(() {
_counter++;
});
}
Widget buildTextField(
TextEditingController controller,
) {
return Container(
key: UniqueKey(),
height: 40.0,
width: 200.0,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(32),
),
child: TextField(
keyboardType: TextInputType.number,
//style: kPhoneAuthTextFields,
decoration: InputDecoration(
hintStyle: TextStyle(color: Colors.orange),
hintText: controller.text,
suffixIcon: Icon(
Icons.phone_android,
size: 20,
color: Colors.white,
),
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 5.0, left: 30.0),
),
onChanged: (value) {
controller.text = value;
},
),
);
}
Widget buildRaisedButton(String label, Function callback) {
return Container(
height: 40.0,
width: 100.0,
child: RaisedButton(
child: Text(
label,
//style: kPhoneLoginTextStyle,
),
color: Colors.blue,
//padding: EdgeInsets.all(8.0),
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(40.0)),
onPressed: callback,
),
);
}
resetCallback() {
print('cleared ....');
setState(() {
phoneController.clear();
otpController.clear();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buildTextField(phoneController),
buildTextField(otpController),
buildRaisedButton('Reset', resetCallback),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Related
I have one login page .dart that contains 3 seperate object class dart such as : InputEmail , Password and ButtonLogin which its split each other but it's called together in login page
My problem is how can i validate form input email and password when i submit the button login when field is empty and email not valid
I tried to create Globalkey FormState inside login page and call it on button login class dart though
Onpressed event but nothing give me error message.
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.redAccent, Colors.lightBlueAccent]),
),
key: _formKey,
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
Row(children: const <Widget>[
VerticalText(),
TextLogin(),
]),
const InputEmail(),
const PasswordInput(),
const ButtonLogin(),
const FirstTime(),
],
),
],
),
),
);
}
}
class ButtonLogin extends StatefulWidget {
const ButtonLogin({Key? key}) : super(key: key);
#override
_ButtonLoginState createState() => _ButtonLoginState();
}
class _ButtonLoginState extends State<ButtonLogin> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 40, right: 50, left: 200),
child: Container(
alignment: Alignment.bottomRight,
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
boxShadow: const [
BoxShadow(
color: Colors.blue,
blurRadius: 10.0, // has the effect of softening the shadow
spreadRadius: 1.0, // has the effect of extending the shadow
offset: Offset(
5.0, // horizontal, move right 10
5.0, // vertical, move down 10
),
),
],
color: Colors.white,
borderRadius: BorderRadius.circular(30),
),
child: FlatButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'OK',
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
Icon(
Icons.arrow_forward,
color: Colors.lightBlueAccent,
),
],
),
),
),
);
}
}
You can pass the callback of onPressed function of button to Login Page and validate it there.
class ButtonLogin extends StatefulWidget {
const ButtonLogin({Key? key, required this.onPressed}) : super(key: key);
final VoidCallBack onPressed ;
#override
_ButtonLoginState createState() => _ButtonLoginState();
}
class _ButtonLoginState extends State<ButtonLogin> {
#override
Widget build(BuildContext context) {
return Padding(
child: Container(
....
child: FlatButton(
onPressed: widget.onPressed,
child: Row(
...
);
}
}
and change add this onPressed parameter inside ButtonLogin widget on Login page
const InputEmail(),
const PasswordInput(),
const ButtonLogin(onPressed: () {
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
},),
const FirstTime(),
The easy way is to create a single StateFulWidget and within the StateFulWidget, you brake your form Widgets (InputEmail, Password and ButtonLogin) into separate Widget methods(functions). Afterward Wrap them with a Form widget using Row, Column or any Widget that accept list.
Next you add the _formKey to the Form widget. I will advice the use of controller for your inputs. Below is an example using your code. By the way change FlatButton -> TextButton
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
#override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.redAccent, Colors.lightBlueAccent]),
),
child: Form(
key: _formKey,
child: ListView(
children: [
Column(
children: [
// inputEmail(),
// passwordInput(),
buttonLogin(),
],
),
],
),
),
),
);
}
Widget buttonLogin() {
return Padding(
padding: const EdgeInsets.only(top: 40, right: 50, left: 200),
child: Container(
alignment: Alignment.bottomRight,
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30),
boxShadow: const [
BoxShadow(
color: Colors.blue,
blurRadius: 10.0,
spreadRadius: 1.0,
offset: Offset(5.0, 5.0),
),
],
),
child: TextButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Processing Data')),
);
}
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
'OK',
style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
Icon(
Icons.arrow_forward,
color: Colors.lightBlueAccent,
),
],
),
),
),
);
}
}
I was trying to make this page but this design in last is not shifting to the last bottom, I've tried padding but this doesn't look good and also I've tried positioned widget but it is showing some error please someone tell how I can shift that design to bottom last
this is my git repo: https://github.com/cryptic-exe/Otp_verfication
this is my code:
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String dropdownValue = 'English';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Column(
children: [
Icon(
Icons.photo_outlined,
size: 100.0,
),
Padding(
padding: const EdgeInsets.only(top: 40.0),
child: Text(
'Please Select Your Language',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20.0),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
'You can change the language \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t at any time',
style: TextStyle(
fontWeight: FontWeight.w300, fontSize: 15.0),
),
),
Padding(
padding: const EdgeInsets.only(top: 9.0),
child: Container(
width: 200,
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
decoration: BoxDecoration(
border: Border.all(),
),
child: DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_drop_down_outlined),
isExpanded: true,
iconSize: 30,
elevation: 16,
style: const TextStyle(color: Colors.black),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>[
'English',
'Hindi',
'French',
'Spanish',
'Russian',
'Arabic'
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: TextStyle(
fontSize: 20,
letterSpacing: 0.9,
fontWeight: FontWeight.w300),
),
);
}).toList(),
),
),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
width: 200,
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
decoration: BoxDecoration(
color: Colors.deepPurple,
border: Border.all(),
),
child: TextButton(
onPressed: () {},
child: Text(
'NEXT',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w400,
letterSpacing: 0.9),
),
),
),
),
],
),
),
Stack(
children: [
Positioned.fill(
child: Container(
width: 393,
child: Image(
image: AssetImage('Images/design2.png'),
fit: BoxFit.fill,
),
),
),
Positioned(
child: Container(
width: 393,
child: Image(
image: AssetImage('Images/design1.png'),
colorBlendMode: BlendMode.overlay,
fit: BoxFit.fill,
),
),
),
],
),
],
),
);
}
}
you can use bottomSheet to place your image.
Add the below code inside your Scaffold
bottomSheet: Container(
width: double.infinity,
child: Image(
image: AssetImage('Images/design1.png'),
colorBlendMode: BlendMode.overlay,
fit: BoxFit.fill,
),
),
You can also use a spacer to push the content down
https://api.flutter.dev/flutter/widgets/Spacer-class.html
On mobile so I cannot give snippet
I want to change background color of the tabs when it tapped ?
How can I change the color
I have this test project :
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.pink,
bottom: TabBar(
labelColor: Colors.yellow,
indicatorColor: Colors.yellow,
onTap: (index) {
// Should not used it as it only called when tab options are clicked,
// not when user swapped
},
controller: _controller,
tabs: list,
),
title: Text('Tabs Demo'),
),
body: TabBarView(
controller: _controller,
children: List<Widget>.generate(3, (int index){
return Center(
child: Text(index.toString()),
);
}),
),
),
);
You can use the index property of the controller to check which tab is currently active and listen to the controller to know when it changed.
For instance by using an AnimatedBuilder around the Tab widget
These things to consider:
Use tab controller and check indexIsChanging
Wrap text inside Tab with a widget for the color change
Remove labelPadding
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
TabController tabController;
List<Color> tabBackground;
List colors = [Colors.red, Colors.green, Colors.yellow];
Random random = Random();
#override
void initState() {
super.initState();
tabController = TabController(length: 3, vsync: this);
tabBackground = [Colors.blue, Colors.pink, Colors.cyan];
tabController.addListener(() {
if (tabController.indexIsChanging) {
setState(() {
tabBackground[tabController.index] = colors[random.nextInt(3)];
});
}
});
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.pink,
bottom: TabBar(
labelPadding: EdgeInsets.zero,
labelColor: Colors.yellow,
indicatorColor: Colors.black,
controller: tabController,
tabs: [
Tab(
child: Container(
alignment: Alignment.center,
constraints: BoxConstraints.expand(),
color: tabBackground[0],
child: Text(
'Tab 1',
style: TextStyle(
color: Colors.white,
),
),
),
),
Tab(
child: Container(
alignment: Alignment.center,
constraints: BoxConstraints.expand(),
color: tabBackground[1],
child: Text(
'Tab 2',
style: TextStyle(
color: Colors.white,
),
),
),
),
Tab(
child: Container(
alignment: Alignment.center,
constraints: BoxConstraints.expand(),
color: tabBackground[2],
child: Text(
'Tab 3',
style: TextStyle(
color: Colors.white,
),
),
),
),
],
),
title: Text('Tabs Demo'),
),
body: TabBarView(
controller: tabController,
children: List<Widget>.generate(3, (int index) {
return Center(
child: Text(index.toString()),
);
}),
),
);
}
}
I'm working on a Flutter project and I was trying to achieve an AlertDialog similar to the option's dialog specified on MaterialDesign Guidelines, but with a TextInput at the bottom.
I have managed to get something similar to what I want but I there's a problem I can't solve: when the user taps on TextInput and the keyboard appears, I'd like the TextInput to be on top of the keyboard with the listview getting smaller on the y-axis (that's why I'm just setting maxHeight on ConstrainedBox), so that the user can see what he texts, but I'm getting just the opposite, the listview keeps the same size and the InputText is not visible.
I have tried changing the listview with a column nested on a SingleChildScrollView, or wrapping the entire original Column on a SingleChildScrollView, but none of them seems to work.
This is my current code:
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(widget.title),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))
),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
widget.onCancel();
},
),
FlatButton(
child: const Text('OK'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
widget.onOk();
},
),
],
content: Container(
width: double.maxFinite,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Divider(),
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height*0.4,
),
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.exercises.length,
itemBuilder: (BuildContext context, int index){
return RadioListTile(
title: Text(widget.exercises[index].name),
value: index,
groupValue: _selected,
onChanged: (value){
setState(() {
_selected = index;
});
}
);
}
),
),
Divider(),
TextField(
autofocus: false,
maxLines: 1,
style: TextStyle(fontSize: 18),
decoration: new InputDecoration(
border: InputBorder.none,
hintText: widget.hintText,
),
),
],
),
),
);
}
Could somebody provide me some help?
Thanks a lot!!
You can copy paste run full code below
You can in content use SingleChildScrollView
code snippet
content: SingleChildScrollView(
child: Container(
width: double.maxFinite,
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class Exercise {
String name;
Exercise({this.name});
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
List<Exercise> exercises = [
Exercise(name: 'A'),
Exercise(name: 'B'),
Exercise(name: 'C'),
Exercise(name: 'D'),
Exercise(name: 'E'),
Exercise(name: 'F'),
Exercise(name: 'G')
];
int _selected;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(widget.title),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20))),
actions: <Widget>[
FlatButton(
child: const Text('CANCEL'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
//widget.onCancel();
},
),
FlatButton(
child: const Text('OK'),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Theme.of(context).accentColor,
onPressed: () {
//widget.onOk();
},
),
],
content: SingleChildScrollView(
child: Container(
width: double.maxFinite,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Divider(),
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.4,
),
child: ListView.builder(
shrinkWrap: true,
itemCount: exercises.length,
itemBuilder: (BuildContext context, int index) {
return RadioListTile(
title: Text(exercises[index].name),
value: index,
groupValue: _selected,
onChanged: (value) {
setState(() {
_selected = index;
});
});
}),
),
Divider(),
TextField(
autofocus: false,
maxLines: 1,
style: TextStyle(fontSize: 18),
decoration: new InputDecoration(
border: InputBorder.none,
hintText: "hint",
),
),
],
),
),
),
);
}
}
how to animate the added containers as soon as they appear ? ( animation of height going from 0 to containerHeight)
here is a code to illustrate my question:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
List<Widget> widgetList = [Container()];
class _HomeState extends State<Home> {
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animated container'),
backgroundColor: Colors.blue,
),
body: Container(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Center(
child: Padding(
//shift to left
padding: const EdgeInsets.only(left: 55.0),
child: Row(
children: widgetList.toList(),
),
),
),
],
),
),
FlatButton(
child: Text(
'Add',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
add(controller.text);
});
},
color: Colors.blue,
),
FlatButton(
child: Text(
'Clear',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
widgetList.clear();
});
},
color: Colors.blue,
),
TextField(
onChanged: (text) {},
textAlign: TextAlign.center,
controller: controller,
keyboardType: TextInputType.number,
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
fontWeight: FontWeight.w300),
decoration: InputDecoration(
hintStyle: TextStyle(
color: Colors.white, fontWeight: FontWeight.w300),
fillColor: Colors.blue,
filled: true,
),
),
]),
),
);
}
}
void add(String containerHeight) {
widgetList.add(Padding(
padding: const EdgeInsets.all(3.0),
child: AnimatedContainer(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(2.0),
),
duration: Duration(milliseconds: 165),
alignment: Alignment.center,
//color: Colors.red,
height: double.parse(containerHeight),
width: 29.0,
child: Text(
containerHeight,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: containerHeight.length == 1
? 19.0
: containerHeight.length == 2
? 19.0
: containerHeight.length == 3
? 16.0
: containerHeight.length == 4 ? 14.0 : 10.0),
),
)));
}
Screenshot of the ui
You just have to put the height of the container in the text field and press 'add', then the containers will appear directly without animation,
so my question is how to animate so that the height goes from 0 to containerHeight ?
i know it works when the widget is already there and we modify it's height, but i couldn't figure out how to do in that scenario ( adding to a list and displaying it directly ).
thank you.
Try the following code. It is working.
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
List<Widget> widgetList = [Container()];
StreamController<String> animationStream = StreamController();
class _HomeState extends State<Home> {
TextEditingController controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animated container'),
backgroundColor: Colors.blue,
),
body: Container(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Center(
child: Padding(
//shift to left
padding: const EdgeInsets.only(left: 55.0),
child: Row(
children: widgetList.toList(),
),
),
),
],
),
),
FlatButton(
child: Text(
'Add',
style: TextStyle(color: Colors.white),
),
onPressed: () {
animationStream = StreamController();
setState(() {
add("0");
animationStream.sink.add(controller.text);
});
},
color: Colors.blue,
),
FlatButton(
child: Text(
'Clear',
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
widgetList.clear();
});
},
color: Colors.blue,
),
TextField(
onChanged: (text) {},
textAlign: TextAlign.center,
controller: controller,
keyboardType: TextInputType.number,
style: TextStyle(
color: Colors.white,
fontSize: 25.0,
fontWeight: FontWeight.w300),
decoration: InputDecoration(
hintStyle: TextStyle(
color: Colors.white, fontWeight: FontWeight.w300),
fillColor: Colors.blue,
filled: true,
),
),
]),
),
);
}
}
void add(String containerHeight) {
widgetList.add(new MyWidget());
}
class MyWidget extends StatelessWidget {
const MyWidget({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: animationStream.stream,
builder: (context, snapshot) {
String _hight = "0";
if (snapshot.hasData ) {
_hight = snapshot.data;
try { double.parse(_hight);} catch (e) { print('please enter a valid hight');_hight="0"; }
}
return Padding(
padding: const EdgeInsets.all(3.0),
child: AnimatedContainer(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(2.0),
),
duration: Duration(milliseconds: 2165),
alignment: Alignment.center,
//color: Colors.red,
height: double.parse(_hight),
width: 29.0,
child: Text(
_hight,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: _hight.length == 1
? 19.0
: _hight.length == 2
? 19.0
: _hight.length == 3
? 16.0
: _hight.length == 4 ? 14.0 : 10.0),
),
));
},
);
}
}