how to add loader when on the toggle button - flutter

I want to display a circular loader when user is going to on the toggle button, then after few secs toggle button will active.
here is my code
InkWell(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ProductProfile(),
));
},
child: Container(
decoration: BoxDecoration(
color: _selectedProducts.contains(book.id) ? Colors.grey[200] :Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
child: ListTile(
dense: true,
trailing: Switch(
value: _selectedProducts.contains(book.id),
onChanged: (bool? selected) {
if (selected != null) {
setState(() {
_onProductSelected(selected, book.id);
});
}
},
activeTrackColor: HexColor("#b8c2cc"),
activeColor: HexColor("#7367f0"),
),
title: Text(
book.title,),
Divider()
),
),
),
SizedBox10(),
],
);
please help how to do this

To achieve that, you need bool _isLoading and a timer. Steps I would do:
Declare _isLoading: bool _isLoading = false;
Change _isLoading value using a timer:
void timer() {
int _time = 10;
Timer timer = new Timer.periodic(
Duration(seconds: 1),
(Timer timer) async {
if (_time == 0) {
_isLoading = true;
timer.cancel();
} else {
setState(() {
_time--;
});
}
},
);
}
Use _isLoading on your build method (for example):
#override
Widget build(BuildContext context) {
return _isLoading ? CircularProgressIndicator() : Container();
}
Or to hide your button:
#override
Widget build(BuildContext context) {
return _isLoading ? Container() : YourToggleButton;
}
Also remember to dispose your timer!
#override
void dispose() {
timer.cancel();
}

So, If you are on Flutter web, there is a widget called MouseRegion which has onHover, onEnter & onExit.
You can assign a new bool for instance bool showLoader=false which you will toggle to true with setState (inside the onHover, where you could also start the Timer and when finished reset the showLoader to false).
Now you can show your button with a ternary operator : showLoader ? CircularProgressIndicator() : YourButton()

Related

Flutter async await skiping to next function

Trying to make a button which replace text with circlularprogressIndication. when task or function done and not working properly
is there any function called Whencompleted or something pls susggest
class Continue extends StatefulWidget {
const Continue({Key? key, required this.ontap}) : super(key: key);
final Function ontap;
#override
State<Continue> createState() => _ContinueState();
}
class _ContinueState extends State<Continue> {
bool loading = false;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () async {
setState(() {
loading = true;
});
await widget.ontap();
setState(() {
loading = false;
});
},
child: Container(
width: 180.w,
height: 50.h,
decoration: BoxDecoration(
color: Theme.of(context).primaryColorDark,
borderRadius: const BorderRadius.all(Radius.circular(4)),
),
child: Padding(
padding: EdgeInsets.all(8.sp),
child: Center(
child: loading == true
? CircularProgressIndicator(
color: Theme.of(context).primaryColor,
)
: ResponsiveText(
text: 'Continue',
maxLines: 1,
centered: true,
size: 16,
style: TextStyle(color: Theme.of(context).primaryColor),
),
),
),
),
);
}
}
And my ontap function is:
ontap:() {
Timer(Duration(seconds: 3), () {
setState(() {
otpActive = true;
});
});
},
Function is not async, if you want to do something in async you should use Future so change to this:
final Future<void> Function() ontap;
and also in your ontap do this:
ontap: ()async{
await Future.delayed(Duration(seconds: 3));
setState(() {
otpActive = true;
});
},
Just use Future.delayed instead of Timer in your OnTap function:
() async {
await Future.delayed(Duration(seconds: 3), () {
setState(() {
otpActive = true;
});
});
}

CircularProgressIndicator not stopping while moving back

Created a demo for understanding future..
I have taken two screen....Using Future.delayed I am forwarding to next screen in 5 seconds with CircularProgressIndicator...but when I move to back..it still showing CircularProgressbar...
What should I correct my code?
here is my code
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
// TODO: implement initState
super.initState();
}
bool isloading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Async demo'),
),
body: isloading == true
? Center(child: CircularProgressIndicator())
: Center(
child: TextButton(
child: Text('Pressed'),
onPressed: () {
setState(() {
isloading = true;
});
Future.delayed(Duration(seconds: 5), () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return NextScreen();
}));
isloading = false;
});
},
),
),
);
}
}
What should I correct my code?
Wrap the second assignment of isloading to false inside setState (just as you did when setting to true). Something like the following:
onPressed: () {
setState(() {
isloading = true;
});
Future.delayed(Duration(seconds: 5), () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return NextScreen();
}));
setState(() {
isloading = false;
});
});
},
you need to use setState when you are assign variable = false
For that do as below
replace this
isloading = false;
with
setState(() {
isloading = false;
});

How to set state using button click in flutter?

I have a boolean isUserLoggedIn = false; in my main.dart file and when isUserLoggedIn = false i am loading
Widget build(BuildContext context) {
return Scaffold(
body: isUserLoggedIn == false ? IntroAuthScreen() : HomePage(),
);
This is working fine. IntroAuthScreen is loading. But there is a button in IntroAuthScreen i want the value of isUserLoggedIn to be true when user click the button and he will be redirected to HomePage() as above code show.
IntroAuthCode:-
child: ElevatedButton.icon(
icon: Icon(
Icons.navigate_next,
color: Colors.white,
),
onPressed: () {
setState(() {
username = usernameController.text;
isUserLoggedIn = true;
});
print(username);
Navigator.pop(context);
},
label: Text("Finish"),
),
but its not working. help me
What if you try to create a wrapper class rather than switching the content of the scaffold?
Perhaps something like this:
class AuthWrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final _user = Provider.of<User>(context);
return (_user == null) ? IntroAuthScreen() : HomeScreen();
}
}
The answer does make use of Provider, but it's definitely a worthwhile package to consider learning.
Check Below code.
Widget build(BuildContext context) {
return Scaffold(
body: isUserLoggedIn == false ? IntroAuthScreen() : HomePage(),
);
IntroAuthScreen() async {
bool isLoggedIN = await Navigator.push(MaterialPageRoute Bla Bla);
setState((){
isUserLoggedIn = isLoggedIN ?? false;
});
}
}
In Auth Code
child: ElevatedButton.icon(
icon: Icon(
Icons.navigate_next,
color: Colors.white,
),
onPressed: () {
setState(() {
username = usernameController.text;
isUserLoggedIn = true;
});
print(username);
Navigator.pop(context, isUserLoggedIn);
},
label: Text("Finish"),
),

Disabled button when textInputField is invalid on change text Flutter

I'm new on Flutter.
I'm trying to disabled button while I compile textFormField and it is invalid.
My problem is that it works only if I click on "confirm" on keyboard and not while I compile my input.
So would like disable button while I write the input.
I've done a pastebin for example:
https://pastebin.com/q5WuwrCm
class AddCartButton extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return AddCartButtonState();
}
}
class AddCartButtonState extends State<AddCartButton>{
TextEditingController myController = TextEditingController();
bool isValid = false;
#override
Widget build(BuildContext context) {
void _addToCart(){
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("QUANTITY"),
content: Column(
children: <Widget>[
TextFormField(
controller: myController,
decoration: new InputDecoration(labelText: "quantity"),
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: <TextInputFormatter>[],
autovalidate: true,
validator: (value) {
if (value.isEmpty) {
isValid = false;
return "the quantity cannot be empty";
} else if (double.tryParse(value) == null) {
isValid = false;
return "the quantity must be valid number";
} else {
isValid = true;
return null;
}
}
)
],
),
actions: <Widget>[
FlatButton(
disabledTextColor: Colors.grey,
child: Text("add"),
onPressed: isValid ? () { print("is valid"); }: null
)
],
);
},
);
}
}
}
You can use addListener() function on your TextEditingController myController.
myController.addListener((){
//With this, you can "listen" all the changes on your text while
//you are typing on input
print("value: ${myController.text}");
//use setState to rebuild the widget
setState(() {
//you can check here if your text is valid or no
//_isValidText() is just an invented function that returns
//a boolean representing if the text is valid or not
if(_isValidText(myController.text)) isValid = true;
else isValid = false;
});
});
If I understood what you want to achieve the following code works for you. The conditions I set are the same as your validation rules:
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TextEditingController _textEditingController = TextEditingController();
Function _submitFunction;
// We need a reusable timer and it needs to not be null so that we can cancel it from th start.
Timer _timer = Timer(Duration(milliseconds: 1), () => print('initialTimer'));
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Auto disable button'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
controller: _textEditingController,
onChanged: (text) {
setState(() {
_submitFunction = null;
});
restartTimer();
},
),
RaisedButton(
child: Text('Submit'),
onPressed: _submitFunction,
),
],
),
),
)
);
}
void submitForm(){
print(_textEditingController.text);
}
void enableButton(){
if(_textEditingController.text != ''){
setState(() {
_submitFunction = submitForm;
});
}
}
void restartTimer(){
_timer.cancel();
_timer = Timer(Duration(milliseconds: 1500), enableButton);
}
}
You can use this method .
bool isEnable = false;
void validateButton() {
bool isValid = true;
isValid = userEmail.isNotEmpty &&
userPassword.isNotEmpty &&
validateEmail(userEmail) &&
userPassword.length >= 8;
setState(() {
isEnable = isValid;
});
}
now in your Textfield onChanged method you have to call this function
like This
onChanged: (email) {
userEmail = email;
setState(() {});
validateButton();
},
and in your Login Button
isEnable?ActiveButton():DisableButton()

How to update variable from TextFormField in flutter?

I have TextFormField which has its own controller. I also have a disabled button that I would like to enable after any input inside TextFormField. The problem is that I managed to enable the button however only when I close the keyboard. For example, if I'm typing a word in a session it won't enable the button unless I close the keyboard. I would like to enable the button after the first character.
This is the code:
final TextEditingController passwordController = new TextEditingController();
TextFormField(
keyboardType: TextInputType.visiblePassword,
controller: passwordController,
),
RaisedButton(
onPressed: (passwordController.text== "") ? null : () {
setState(() {
_isLoading = true;
});
signIn(email, passwordController.text);
},
),
Is this what you're looking for?
final TextEditingController _controller = TextEditingController();
bool _isLoading = true;
// it tracks if TextField is enabled or disabled
bool _enabled = false;
#override
void initState() {
super.initState();
_controller.addListener(() { // you need to add listener like this
setState(() {
if (_controller.text.length > 0)
_enabled = true;
else
_enabled = false;
});
});
}
Widget build(context) {
return Scaffold(
body: Column(
children: <Widget>[
SizedBox(height: 50),
TextFormField(controller: _controller),
RaisedButton(
onPressed: !_enabled ? null : () => setState(() => _isLoading = true),
),
],
),
);
}
Based on what you're looking for, I created a boolean called isEnabled and set the initial value to false. This should work for you!
bool isEnabled;
final TextEditingController passwordController = new TextEditingController();
#override
void initState() {
super.initState();
passwordController.addListener(() {
setState(() {
if (passwordController.text.length > 0) {
isEnabled = true;
} else {
isEnabled = false;
}
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.visiblePassword,
controller: passwordController,
),
RaisedButton(
child: Text('Click Me'),
onPressed: isEnabled ? () {
//print('Button has been pressed');
setState(() {
_isLoading = true;
});
signIn(email, passwordController.text);
} : null,
),
],
),
);
}
This worked:
var password = '';
TextFormField(
keyboardType: TextInputType.visiblePassword,
controller: passwordController,
onChanged: (value){
setState(() {
password = value;
});
},
),
RaisedButton(
onPressed: (password == "") ? null : () {
setState(() {
_isLoading = true;
});
signIn(email, password);
},
),