What is The proper way to animate a widget in flutter - android

I have tried a lot of packages like Animated Size And Fade and a widget like AnimatedSwitcher and nothing really worked, they just change the widget without animation .. here is my code :
AnimatedSwitcher(
duration: Duration(milliseconds: 1),
child: isCompany
? Container(
key: ValueKey<int>(0),
child: Padding(
padding: const EdgeInsets.fromLTRB(40, 0, 40, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextField(
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.white),
),
prefixIcon: Image.asset(
'assets/images/user_icon.png'),
labelText: 'إسم المستخدم',
labelStyle: TextStyle(
color: Colors.white, fontSize: 18)),
),
TextField(
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.white),
),
prefixIcon: Image.asset(
'assets/images/password_icon.png'),
suffixIcon: IconButton(
icon: Image.asset(
'assets/images/show_icon.png'),
onPressed: () {},
),
labelText: 'كلمة المرور',
labelStyle: TextStyle(
color: Colors.white, fontSize: 18)),
),
],
),
),
)
: Container(
key: ValueKey<int>(1),
child: Padding(
padding: const EdgeInsets.fromLTRB(40, 40, 40, 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextField(
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.white),
),
prefixIcon: Image.asset(
'assets/images/user_icon.png'),
labelText: 'رقم الجوال',
labelStyle: TextStyle(
color: Colors.white, fontSize: 18)),
),
TextField(
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.white),
),
prefixIcon: Image.asset(
'assets/images/password_icon.png'),
suffixIcon: IconButton(
icon: Image.asset(
'assets/images/show_icon.png'),
onPressed: () {},
),
labelText: 'كلمة المرور',
labelStyle: TextStyle(
color: Colors.white, fontSize: 18)),
),
],
),
),
)
),
This is just changing widget with a click, no animation at all, and I need it to be like this video :
https://youtu.be/Uwe8hHkfd8I

AnimatedSwitcher just switches betwween the widget it displays.
One idea I had thinking about your problem is using a stack with two Positioned Items as your Buttons and one PositionedTransition, that translates between the position of your first and second Positioned Widgets when pressed.
Have a look at this example: https://api.flutter.dev/flutter/widgets/PositionedTransition-class.html
Now I had time to do a quick and easy example of my idea that looks like this:
(It does not lag - this is caused by the conversion of video to gif)
Code that you can copy paste as basis:
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(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
AnimationController _controller;
final double containerWidth = 150.0;
final double containerHeight = 50.0;
final double padding = 20.0;
final double borderWidth = 5.0;
#override
void initState() {
super.initState();
_controller =
AnimationController(duration: Duration(seconds: 1), vsync: this);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: LayoutBuilder(builder: (context, constraints) {
final Size biggest = constraints.biggest;
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.white,
child: Stack(
children: [
PositionedTransition(
rect: RelativeRectTween(
begin: RelativeRect.fromSize(
Rect.fromLTWH(
padding, padding, containerWidth, containerHeight),
biggest),
end: RelativeRect.fromSize(
Rect.fromLTWH(biggest.width - containerWidth - padding,
padding, containerWidth, containerHeight),
biggest),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
)),
child: Container(
width: containerWidth,
height: containerHeight,
decoration:
BoxDecoration(border: Border.all(width: borderWidth)),
),
),
Positioned(
top: padding + borderWidth,
left: padding + borderWidth,
child: GestureDetector(
onTap: () {
_controller.reverse();
},
child: Container(
width: containerWidth - 2 * borderWidth,
height: containerHeight - 2 * borderWidth,
child: Center(
child: Text(
"Text1",
style: TextStyle(color: Colors.black, fontSize: 20),
),
),
),
)),
Positioned(
top: padding + borderWidth,
left: biggest.width - containerWidth - padding + borderWidth,
child: GestureDetector(
onTap: () {
_controller.forward();
},
child: Container(
width: containerWidth - 2 * borderWidth,
height: containerHeight - 2 * borderWidth,
child: Center(
child: Text(
"Text2",
style: TextStyle(color: Colors.black, fontSize: 20),
),
),
),
)),
],
),
);
}),
);
}
}
Future work:
To achieve what you want in the video you could use the AnimatedSwitcher you already tried to just alternate between the two Input fields depending on the button press.

Related

The parameter 'size' can't have a value of 'null' because of its type in Dart

I am new to flutter and dart , I have a problem where the parameter size cant have null value. I tried to search in the google the same problem that people had been facing and the solution is to add 'required'. i had tried that but the problem is in my body
Below here is my CustomCard().
import 'package:flutter/material.dart';
import '../../constants.dart';
class CustomCard extends StatefulWidget {
final Size size;
final Icon icon;
final String title, statusOn, statusOff;
const CustomCard(
{ required Key key,
required this.size,
required this.icon,
required this.title,
required this.statusOn,
required this.statusOff})
: super(key: key);
#override
_CustomCardState createState() => _CustomCardState();
}
class _CustomCardState extends State<CustomCard>
with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<Alignment> _animation;
bool isChecked = true;
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 350),
);
_animation = Tween<Alignment>(
begin: Alignment.bottomCenter, end: Alignment.topCenter)
.animate(
CurvedAnimation(
parent: _animationController,
curve: Curves.linear,
reverseCurve: Curves.easeInBack,
),
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
height: 140,
width: widget.size.width * 0.35,
decoration: BoxDecoration(
color: kBgColor,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 8,
offset: Offset(3, 3),
),
BoxShadow(
color: Colors.white,
blurRadius: 8,
offset: Offset(-3, -3),
),
],
),
child: Padding(
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
widget.icon,
AnimatedBuilder(
animation: _animationController,
builder: (animation, child) {
return GestureDetector(
onTap: () {
setState(() {
if (_animationController.isCompleted) {
_animationController.animateTo(20);
} else {
_animationController.animateTo(0);
}
isChecked = !isChecked;
});
},
child: Container(
height: 40,
width: 25,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey.shade50,
boxShadow: [
BoxShadow(
color: Colors.grey.shade200,
blurRadius: 0,
offset: Offset(3, 3),
),
BoxShadow(
color: Colors.black12,
blurRadius: 5,
offset: Offset(-3, -3),
),
],
),
child: Align(
alignment: _animation.value,
child: Container(
height: 15,
width: 15,
margin: EdgeInsets.symmetric(
vertical: 2, horizontal: 1),
decoration: BoxDecoration(
color: isChecked
? Colors.grey.shade300
: kGreenColor,
shape: BoxShape.circle,
),
),
),
),
);
},
),
],
),
SizedBox(height: 10),
Text(
widget.title,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: kBlueColor,
),
),
Text(
isChecked ? widget.statusOff : widget.statusOn,
style: TextStyle(
fontWeight: FontWeight.bold,
color: kGreenColor,
),
),
],
)),
);
}
}
And below here is my Body.dart
import 'package:flutter/material.dart';
import 'package:neew/constants.dart';
import 'package:neew/MainScreen/custom_card.dart';
class MainScreenBody extends StatefulWidget {
#override
_MainScreenBodyState createState() => _MainScreenBodyState();
}
class _MainScreenBodyState extends State<MainScreenBody> {
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
SizedBox(height: size.height * 0.1),
Center(
child: Text(
"My Home",
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 25,
),
),
),
SizedBox(height: size.height * 0.05),
CustomCard(
size: size,
icon: Icon(
Icons.home_outlined,
size: 55,
color: Colors.grey.shade400,
),
title: 'Entry',
statusOn: 'OPEN',
statusOff: 'LOCKED',
)
],
),
);
}
}
The error that i detect in body dart is in CustomCard().
Please help me, I will really appreciate it.

Flutter double parsing error Invalid double

I'm having trouble with this code which is giving me this error.
I'm really new to flutter and this is my first project.
import 'dart:ffi';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: BmiCalculator(),
);
}
}
//create a statefull widget
class BmiCalculator extends StatefulWidget {
BmiCalculator({Key key}) : super(key: key);
#override
_BmiCalculatorState createState() => _BmiCalculatorState();
}
class _BmiCalculatorState extends State<BmiCalculator> {
int currentindex = 0;
double result = 0;
double height = 0;
double weight = 0;
TextEditingController heightController = TextEditingController();
TextEditingController weightController = TextEditingController();
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
appBar: AppBar(
title: Text("BMI Calculator", style: TextStyle(color: Colors.black),),
elevation: 0.0,
backgroundColor: Color(0xfffafafa),
actions: [
IconButton(
onPressed: () {},
icon: Icon(
Icons.settings,
color: Colors.black,
)
)
],
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
radioButton("Man", Colors.blue, 0),
radioButton("Woman", Colors.pink, 1),
],
),
SizedBox(
height: 20.0 ,
),
Text(
"Your Height in CM" ,
style: TextStyle(
fontSize: 18.0,
),
),
SizedBox(
height: 8.0,
),
TextField(
keyboardType: TextInputType.number,
controller: heightController,
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: "Your Height In CM",
filled: true,
fillColor: Colors.grey[200],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide.none,
),
),
),
SizedBox(
height:20.0,
),
Text(
"Your Weight in KG" ,
style: TextStyle(
fontSize: 18.0,
),
),
SizedBox(
height: 8.0,
),
TextField(
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: "Your Weight In KG",
filled: true,
fillColor: Colors.grey[200],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide.none,
),
),
),
SizedBox(height: 20.0,),
Container(
width: double.infinity,
height: 50.0,
child: FlatButton(
onPressed: () {
setState(() {
height = double.parse(heightController.value.text);
weight = double.parse(weightController.value.text);
});
calculateBmi(height, weight);
},
color: Colors.blue,
child:Text("Calculate", style: TextStyle(
color: Colors.white,
)),
),
),
SizedBox(
height: 20.0,
),
Container(
width: double.infinity,
child: Text(
"Your BMI is : ",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
)
)
),
SizedBox(
height: 50.0,
),
Container(
width: double.infinity,
child: Text(
"$result",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 40.0,
fontWeight: FontWeight.bold,
)
)
),
],
),
),
)
),
);
}
void calculateBmi(double height, double weight){
double finalresult = weight / (height * height / 10000);
double bmi = finalresult;
setState(() {
result = bmi;
});
}
void changeIndex(int index){
setState(() {
currentindex = index;
});
}
Widget radioButton(String value, Color color, int index){
return Expanded(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 12.0),
height: 80.0,
child: FlatButton(
color: currentindex == index ? color : Colors.grey[200],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
onPressed: () {
changeIndex(index);
},
child: Text(value, style: TextStyle(
color: currentindex == index ? Colors.white : color,
fontSize: 22.0,
fontWeight: FontWeight.bold,
)),
)
),
);
}
}
and this is the error:
════════ Exception caught by gesture ═══════════════════════════════════════════════════════════════
The following FormatException was thrown while handling a gesture:
Invalid double
When the exception was thrown, this was the stack:
#0 double.parse (dart:core-patch/double_patch.dart:111:28)
#1 _BmiCalculatorState.build.. (package:lab1_flutter/main.dart:129:41)
#2 State.setState (package:flutter/src/widgets/framework.dart:1244:30)
#3 _BmiCalculatorState.build. (package:lab1_flutter/main.dart:127:23)
#4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#50a78
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(150.6, 444.6)
finalLocalPosition: Offset(138.6, 36.6)
button: 1
sent tap down
════════════════════════════════════════════════════════════════════════════════════════════════════
What is happening on line 129 ?
Can you tell us what is displayed by changing this code ?
setState(() {
print(heightController.value.text);
print(weightController.value.text);
height = double.parse(heightController.value.text);
weight = double.parse(weightController.value.text);
});
My guess is that you use heightController in the TextField, but not weightController, so its value is null, so it throw an error when you parse it.

After using "pushReplacementNamed" in flutter I cannot push this Route again

I have problems using the Navigation in Flutter with the MVVM pattern.
I have two Views:
Login
Dashboard
I Navigate with Navigator.pushReplacementNamed(context, Dashboard) from Login to Dashboard.
When the user loggs out I naviagte from Dashboard to Login with Navigator.pushReplacementNamed(context, Login)
But the i get the following error:
A Login ViewModel was used after being disposed. Once you have called dispose() on a LoginViewModel, it can no longer be used.
I thought that a View\Widget is created when i call it again after it was disposed?
What should i do? It makes no sense to Navigate with
pushNamed
and leave the widget in the widget tree.
My LoginView:
import 'package:app/common/routing_contstants.dart';
import 'package:app/core/viewmodels/views/login_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_signin_button/button_view.dart';
import 'package:flutter_signin_button/flutter_signin_button.dart';
import 'package:app/common/colors.dart';
import 'base_view.dart';
class LoginView extends StatefulWidget {
#override
_LoginView createState() => _LoginView();
}
class _LoginView extends State<LoginView> {
final TextEditingController _mailCtr = TextEditingController();
final TextEditingController _passCtr = TextEditingController();
#override
Widget build(BuildContext context) {
return BaseView<LoginViewModel>(
builder: (context, model, child) => Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
// Add box decoration
decoration: BoxDecoration(
// Box decoration takes a gradient
gradient: LinearGradient(
// Where the linear gradient begins and ends
begin: Alignment.topRight,
end: Alignment.bottomCenter,
// Add one stop for each color. Stops should increase from 0 to 1
stops: [0.2, 0.4, 0.6, 1.0],
colors: [
Colors.deepPurple[800],
Colors.deepPurple[700],
Colors.deepPurple[500],
Theme.of(context).colorScheme.pink,
],
),
),
child: Center(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: <Widget>[
SizedBox(
height: 120,
),
Image.asset(
"assets/images/icon.png",
color: Colors.white,
width: 200,
height: 100,
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _mailCtr,
decoration: InputDecoration(
hintText: "Email",
hintStyle: TextStyle(color: Colors.grey[500]),
icon: Icon(
Icons.email,
color: Colors.white,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
),
cursorColor: Colors.white,
style: TextStyle(color: Colors.white),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _passCtr,
decoration: InputDecoration(
hintText: "Password",
hintStyle: TextStyle(color: Colors.grey[500]),
icon: Icon(
Icons.lock,
color: Colors.white,
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
),
cursorColor: Colors.white,
style: TextStyle(color: Colors.white),
obscureText: true,
),
),
GestureDetector(
onTap: () {},
child: Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: new Text("Forget Password?",
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Colors.white)),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: double.infinity,
child: OutlineButton(
child: Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: new Text("Login",
style: Theme.of(context)
.textTheme
.title
.copyWith(color: Colors.white))),
onPressed: () async {
var loginSuccess = await model.signInWithEmailAndPassword(context, _mailCtr.text, _passCtr.text);
if (loginSuccess != null) {
Navigator.pushReplacementNamed(context, DashboardRoute);
}
},
// color: Colors.blue,
textColor: Colors.white,
borderSide: BorderSide(color: Colors.white),
)),
),
Padding(
padding: const EdgeInsets.all(0.8),
child: SignInButton(
Buttons.Google,
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.all(0.8),
child: SignInButton(
Buttons.Facebook,
onPressed: () {},
),
),
SizedBox(
height: 100,
),
],
),
),
)),
),
),
);
}
}
My DashboardView:
import 'package:app/common/routing_contstants.dart';
import 'package:app/core/viewmodels/views/dashboard_view_model.dart';
import 'package:flutter/material.dart';
import 'package:app/common/colors.dart';
import 'base_view.dart';
class DashboardView extends StatefulWidget {
#override
_DashboardView createState() => _DashboardView();
}
class _DashboardView extends State<DashboardView> {
#override
Widget build(BuildContext context) {
return BaseView<DashboardViewModel>(
builder: (context, model, child) => Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
// Add box decoration
decoration: BoxDecoration(
// Box decoration takes a gradient
gradient: LinearGradient(
// Where the linear gradient begins and ends
begin: Alignment.topRight,
end: Alignment.bottomCenter,
// Add one stop for each color. Stops should increase from 0 to 1
stops: [0.3, 0.7, 0.4, 0.3],
colors: [
Theme.of(context).colorScheme.blue,
Theme.of(context).colorScheme.darkBlue,
Theme.of(context).colorScheme.pink,
Colors.pink[600],
],
),
),
child: Center(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: <Widget>[
SizedBox(height: 32.0),
SizedBox(
height: 50.0,
child: _signOutButton(context, model),
),
SizedBox(height: 30.0),
SizedBox(
height: 100,
),
],
),
),
),
),
),
),
);
}
Widget _signOutButton(context, DashboardViewModel model) {
return OutlineButton(
child: Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: new Text("Logout",
style: Theme.of(context)
.textTheme
.title
.copyWith(color: Colors.white))),
onPressed: () async {
await model.signOut(context).then(
(_) => {
Navigator.pushReplacementNamed(context, LoginRoute)
},
);
},
// color: Colors.blue,
textColor: Colors.white,
borderSide: BorderSide(color: Colors.white),
);
}
}
My BaseView:
import 'package:app/common/locator.dart';
import 'package:app/core/viewmodels/base_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class BaseView<T extends BaseModel> extends StatefulWidget {
final Widget Function(BuildContext context, T model, Widget child) builder;
final Function(T) onModelReady;
BaseView({this.builder, this.onModelReady});
#override
_BaseViewState<T> createState() => _BaseViewState<T>();
}
class _BaseViewState<T extends BaseModel> extends State<BaseView<T>> {
T model = getIt<T>();
#override
void initState() {
if (widget.onModelReady != null) {
widget.onModelReady(model);
}
super.initState();
}
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<T>(
create: (context) => model,
child: Consumer<T>(builder: widget.builder));
}
}
User Factory instead of RegisterLazySingleton.

How to show a Count down Timer within and Alertbox in flutter

i have a Flutter app which should show a counting down timer in an alert box for Phone code confirming (i need this timer to resend the code to my user when 60 second is up) , i start timer when i click on Confirm Button , but the problem is that the timer is not showing that he's going down he stills with a fixed value.
here is my alert box
Alert Box with timer NOT SHOWING COUNT DOWN
here is my timer Function :
int _counter = 60;
Timer _timer;
void _startTimer(){
_counter = 60;
if(_timer != null){
_timer.cancel();
}
_timer = Timer.periodic(Duration(seconds: 1), (timer){
setState(() {
(_counter > 0) ? _counter-- : _timer.cancel();
});
});
}
here is my alert Box code :
void alertD(BuildContext ctx) {
var alert = AlertDialog(
// title: Center(child:Text('Enter Code')),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
backgroundColor: Colors.grey[100],
elevation: 0.0,
content: Container(
height: 215,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 15),
child: Text(
'Enter Code',
style: TextStyle(
color: Colors.green[800],
fontWeight: FontWeight.bold,
fontSize: 16
),
)),
Container(
height: 70,
width: 180,
child: TextFormField(
style: TextStyle(fontSize: 20,fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.green, width: 0.0)),
),
keyboardType: TextInputType.number,
maxLength: 10,
),
),
SizedBox(
height: 1,
),
Text('00:$_counter'),
SizedBox(height: 15,)
,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {
Navigator.of(ctx).pushNamed(SignUpScreenSecond.routeName);
},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.green,
Colors.grey,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Validate',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.grey,
Colors.green,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Resend',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
)
],
), //new column child
],
),
));
showDialog(
context: ctx,
builder: (BuildContext c) {
return alert;
});
}
that's how i'm calling my alert dialog and my timer when i click Confirm Button :
onTap: () {
_startTimer;
alertD(context);
},
You can copy paste run full code below
You can use StreamBuilder and StreamController
AlertDialog content continually receive stream int from Timer
code snippet
StreamController<int> _events;
#override
initState() {
super.initState();
_events = new StreamController<int>();
_events.add(60);
}
...
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
(_counter > 0) ? _counter-- : _timer.cancel();
print(_counter);
_events.add(_counter);
});
...
content: StreamBuilder<int>(
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
...
Text('00:${snapshot.data.toString()}'),
working demo
full code
import 'package:flutter/material.dart';
import 'dart:async';
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;
StreamController<int> _events;
#override
initState() {
super.initState();
_events = new StreamController<int>();
_events.add(60);
}
Timer _timer;
void _startTimer() {
_counter = 60;
if (_timer != null) {
_timer.cancel();
}
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
//setState(() {
(_counter > 0) ? _counter-- : _timer.cancel();
//});
print(_counter);
_events.add(_counter);
});
}
void alertD(BuildContext ctx) {
var alert = AlertDialog(
// title: Center(child:Text('Enter Code')),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
backgroundColor: Colors.grey[100],
elevation: 0.0,
content: StreamBuilder<int>(
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print(snapshot.data.toString());
return Container(
height: 215,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 15),
child: Text(
'Enter Code',
style: TextStyle(
color: Colors.green[800],
fontWeight: FontWeight.bold,
fontSize: 16),
)),
Container(
height: 70,
width: 180,
child: TextFormField(
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.green, width: 0.0)),
),
keyboardType: TextInputType.number,
maxLength: 10,
),
),
SizedBox(
height: 1,
),
Text('00:${snapshot.data.toString()}'),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {
//Navigator.of(ctx).pushNamed(SignUpScreenSecond.routeName);
},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.green,
Colors.grey,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Validate',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.grey,
Colors.green,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Resend',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
)
],
), //new column child
],
),
);
}));
showDialog(
context: ctx,
builder: (BuildContext c) {
return alert;
});
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
_startTimer();
alertD(context);
},
child: Text('Click')),
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),
),
);
}
}

How to sync the UI with data changes in my code

the code is running correctly but the problem is I don't see the UI changes according to the data. as you may notice from my code, in _buildWidget function my cards are made and the shareTag function in the stack is called but at first, because the variable is not true then container is not visible but after the user click on one of the cards I would expect that the isSelected turns to true and then I could see the container in that stack that but it doesn't happen ... I have debugged the code and I noticed that the isSelected variable turn to right correctly every time the users tap on the card but I don't see any changes on UI
Activity activity;
List<double> _cost;
ActivityPeopleCard({this.activity});
#override
_ActivityPeopleCardState createState() => _ActivityPeopleCardState();
}
class _ActivityPeopleCardState extends State<ActivityPeopleCard> {
int _peopleIndex = -1;
List<int> _peopleIndexes = new List();
List<int> _longPressed = new List();
var _vlContainer;
#override
void initState() {
super.initState();
_vlContainer = myListContainer();
}
#override
Widget build(BuildContext context) {
return _vlContainer;
}
myListContainer() {
return Container(
height: height / 2.6,
child: new GridView.builder(
itemCount: widget.activity.peopleInvolved.length,
gridDelegate:
new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
itemBuilder: (BuildContext context, int index) {
return new GestureDetector(
onTap: () => setState(() => {
_priceSet(index),
_buildWidget(index)
}),
child: _buildWidget(index));
},
),
);
}
_buildWidget(int index) {
bool isSelected = _peopleIndexes.contains(index) ? true : false;
return new Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
elevation: 5.0,
child: Stack(children: <Widget>[
new Container(
height: height / 4,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: height / 15,
height: height / 15,
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(height / 20),
border: Border.all(color: Colors.white, width: 2),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(height / 15),
child: Image.asset(
widget.activity.peopleInvolved[index].imagePath,
fit: BoxFit.fill)), //CircleAvatar(
),
Center(child: Text(widget.activity.peopleInvolved[index].name))
],
),
),
shareTag(index)
]));
}
shareTag(index) {
return GestureDetector(
onLongPress: () => {
enterPrice(index),
},
child: Visibility(
visible: isSelected ? true : false,
child: new Container(
height: height / 2,
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(height / 20),
color: Colors.red.shade500.withOpacity(0.7),
),
child: Center(
child: SizedBox(
width: width / 4,
height: height / 15,
child: Center(
child: AutoSizeText(
"\$${ActivityPeopleCard._cost[index]}",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontFamily: 'Oxygen',
fontSize: height / 25),
maxLines: 1,
minFontSize: 5,
textAlign: TextAlign.center,
),
),
))),
));
}
enterPrice(int index) {
//print("Long Pressed");
showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)),
backgroundColor: Colors.white,
content: Form(
//key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new TextFormField(
initialValue: ActivityPeopleCard._cost[index].toString(),
keyboardType: TextInputType.number,
cursorColor: secondColor,
style: TextStyle(
letterSpacing: 1,
),
autofocus: true,
decoration: new InputDecoration(
focusedBorder: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15.0),
borderSide: new BorderSide(color: secondColor)),
labelStyle: TextStyle(color: firstColor
//decorationColor: Colors.yellow
),
prefixIcon: Icon(
Icons.attach_money,
color: firstColor,
),
labelText: "Cost",
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(15.0),
borderSide: new BorderSide(color: Colors.black87),
),
),
),
],
),
),
);
});
}
}
although I have called the _buildWidget again on onTap function and the isSelected is true the ui is not updated

Categories

Resources