Related
I have a form consisting of nextformfield and elevatedButton. I want to repeat the same form just below on the screen in the same page. I have never tried to do this and it didn't work out, please help.
Here is my code in which I want to do this:
import 'dart:math';
import 'package:flutter/material.dart';
class gradysu extends StatefulWidget {
const gradysu({super.key});
#override
State<gradysu> createState() => _gradysuState();
}
class _gradysuState extends State<gradysu> {
var _formKey = GlobalKey<FormState>();
var x, y, c, d;
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Квадрат'),
backgroundColor: Color.fromARGB(255, 252, 252, 252),
automaticallyImplyLeading: true,
),
body: SingleChildScrollView(
child: Container(
height: 800,
width: 639,
/* decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/image/fon2.png"),
fit: BoxFit.cover,
),
),*/
child: Column(
children: [
Container(
color: Colors.brown,
height: 50.0,
width: 1000.0,
child: Center(
child: const Text(
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16, color: Colors.white),
'Расчёт площади квадрата S=:'))),
Row(children: <Widget>[
Container(
padding: const EdgeInsets.all(10.0),
child: const Text('Введите градусы:',
style: TextStyle(color: Color.fromARGB(255, 0, 0, 0))),
),
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) return 'Задайте градусы';
try {
x = double.parse(value);
} catch (h) {
x;
return h.toString();
}
}))),
]),
const SizedBox(height: 20.0),
Text(
y == null ? '' : ' $y (рад) ',
style: const TextStyle(
fontSize: 20.0, color: Color.fromARGB(255, 0, 0, 0)),
),
const SizedBox(height: 20.0),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
setState(() {
if (x is double) y = ((x * pi) / 180);
});
}
},
style: ElevatedButton.styleFrom(
foregroundColor: Color.fromARGB(255, 235, 235,
235), //change background color of button
backgroundColor:
Colors.brown, //change text color of button
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 5.0,
),
child: const Padding(
padding: EdgeInsets.all(8),
child: Text(
'Вычислить',
style: TextStyle(fontSize: 20),
))),
SizedBox(height: 10.0),
],
),
),
),
),
);
}
}
class gradysu1 extends StatefulWidget {
const gradysu1({super.key});
#override
State<gradysu1> createState() => _gradysu1State();
}
class _gradysu1State extends State<gradysu1> {
var _formKey1 = GlobalKey<FormState>();
var a, c;
#override
Widget build(BuildContext context) {
return Form(
key: _formKey1,
child: Scaffold(
body: SafeArea(
child: Column(children: [
Row(children: <Widget>[
Container(
padding: const EdgeInsets.all(10.0),
child: const Text('Введите градусы:',
style: TextStyle(color: Color.fromARGB(255, 0, 0, 0))),
),
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) return 'Задайте градусы';
try {
a = double.parse(value);
} catch (h) {
a;
return h.toString();
}
}))),
]),
const SizedBox(height: 20.0),
Text(
a == null ? '' : ' $a (рад) ',
style: const TextStyle(
fontSize: 20.0, color: Color.fromARGB(255, 0, 0, 0)),
),
const SizedBox(height: 20.0),
ElevatedButton(
onPressed: () {
if (_formKey1.currentState!.validate()) {
setState(() {
if (c is double) a = ((c * pi) / 180);
});
}
},
style: ElevatedButton.styleFrom(
foregroundColor: Color.fromARGB(
255, 235, 235, 235), //change background color of button
backgroundColor: Colors.brown, //change text color of button
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 5.0,
),
child: const Padding(
padding: EdgeInsets.all(8),
child: Text(
'Вычислить',
style: TextStyle(fontSize: 20),
))),
]))));
}
}
This is what it looks like
And this is how it should look like
I tried to create another class, but flutter just doesn't see it, I tried to add it to the main code, but then he just didn't count, but threw an exception.
Try to create reusable widget or builder method to minimize the snippet/code-dublication.
import 'dart:math';
import 'package:flutter/material.dart';
void main(List<String> args) {
runApp(MaterialApp(
home: gradysu(),
));
}
class gradysu extends StatefulWidget {
const gradysu({super.key});
#override
State<gradysu> createState() => _gradysuState();
}
class _gradysuState extends State<gradysu> {
var _formKey = GlobalKey<FormState>();
var x, y, c, d;
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text('Квадрат'),
backgroundColor: Color.fromARGB(255, 252, 252, 252),
automaticallyImplyLeading: true,
),
body: SingleChildScrollView(
child: Container(
height: 800,
width: 639,
/* decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/image/fon2.png"),
fit: BoxFit.cover,
),
),*/
child: Column(
children: [
Container(
color: Colors.brown,
child: Center(
child: const Text(
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16, color: Colors.white),
'Расчёт площади квадрата S=:'))),
Row(children: <Widget>[
Container(
padding: const EdgeInsets.all(10.0),
child: const Text('Введите градусы:',
style: TextStyle(color: Color.fromARGB(255, 0, 0, 0))),
),
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) return 'Задайте градусы';
try {
x = double.parse(value);
} catch (h) {
x;
return h.toString();
}
},
),
),
),
]),
const SizedBox(height: 20.0),
Text(
y == null ? '' : ' $y (рад) ',
style: const TextStyle(
fontSize: 20.0, color: Color.fromARGB(255, 0, 0, 0)),
),
const SizedBox(height: 20.0),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
setState(() {
if (x is double) y = ((x * pi) / 180);
});
}
},
style: ElevatedButton.styleFrom(
foregroundColor: Color.fromARGB(
255, 235, 235, 235), //change background color of button
backgroundColor: Colors.brown, //change text color of button
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 5.0,
),
child: const Padding(
padding: EdgeInsets.all(8),
child: Text(
'Вычислить',
style: TextStyle(fontSize: 20),
),
),
),
SizedBox(height: 10.0),
/// second item , you can create a build method for this
Row(children: <Widget>[
Container(
padding: const EdgeInsets.all(10.0),
child: const Text('Введите градусы:',
style: TextStyle(color: Color.fromARGB(255, 0, 0, 0))),
),
Expanded(
child: Container(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) return 'Задайте градусы';
try {
x = double.parse(value);
} catch (h) {
x;
return h.toString();
}
},
),
),
),
]),
const SizedBox(height: 20.0),
Text(
y == null ? '' : ' $y (рад) ',
style: const TextStyle(
fontSize: 20.0, color: Color.fromARGB(255, 0, 0, 0)),
),
const SizedBox(height: 20.0),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
setState(() {
if (x is double) y = ((x * pi) / 180);
});
}
},
style: ElevatedButton.styleFrom(
foregroundColor: Color.fromARGB(
255, 235, 235, 235), //change background color of button
backgroundColor: Colors.brown, //change text color of button
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 5.0,
),
child: const Padding(
padding: EdgeInsets.all(8),
child: Text(
'Вычислить',
style: TextStyle(fontSize: 20),
),
),
),
SizedBox(height: 10.0),
],
),
),
),
),
);
}
}
i am trying to update the state of the animated switcher in the middle area. i am trying to do this using a setstate in the lower area. but it does not work.
the first thing i did is to create a variable with a boolean data type in the home class.
then i passed the variable to both the middle area and the lower area
the idea was that if the same variable is passed to the class whose state i am trying to update, and the class with the set state, it would work. but it seems i am wrong. i would appreciate some assistance.
the boolean variable i am trying to make work is the _rep variable
This is the Home widget
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
late AnimationController _animationController;
late AnimationController _controller;
late Animation<Offset> _animation;
late Animation<Offset> _anime;
bool _rep = true;
#override
void initState() {
_animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 2)
);
_animation = Tween<Offset>(
begin:Offset (0.0, 0.0),
end: Offset (0.0,3.0),
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeIn));
_anime = Tween<Offset>(
begin:Offset (0.0, 0.0),
end: Offset (0.0,-0.55),
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeIn));
super.initState();
}
#override
void dispose() {
_animationController.dispose();
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
child: Padding(
padding: EdgeInsets.only(top: 3.h),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TopIcon(icons: Icons.arrow_back, color:Colors.grey.shade300 ,),
SizedBox(
height: 13.h,
width: 13.w,
child: Image.asset('assets/images/download.png')
),
TopIcon(icons: Icons.shopping_bag_outlined, color: Colors.grey.shade300,),
],
),
SizedBox(
height: 3.h,
),
Text('Frappuccino',
style: TextStyle(
fontSize: 27.sp,
fontWeight: FontWeight.bold
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('White Chocolate',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey.shade400
),
),
),
MiddleArea(
controller: _animationController,
animation: _animation,
rep: _rep,
),
LowerArea(controller: _animationController, anime: _anime, rep = _rep),
],
),
),
),
);
}
}
This is the middle area
class MiddleArea extends StatefulWidget {
MiddleArea({Key? key, required this.controller, required this.animation, required this.rep}) : super(key: key);
AnimationController controller;
Animation<Offset> animation;
final bool rep;
#override
State<MiddleArea> createState() => _MiddleAreaState();
}
class _MiddleAreaState extends State<MiddleArea> {
bool _flag = true;
bool _favourite = true;
#override
Widget build(BuildContext context) {
print(widget.rep);
return SizedBox(
height: 52.h,
child: Stack(
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 135.0),
child: Text('STARBUCKS',
style: TextStyle(
fontFamily: 'Typette',
color: Colors.brown.shade200,
fontSize: 30.sp,
fontWeight: FontWeight.w400
),
),
),
Text('STARBUCKS',
style: TextStyle(
fontFamily: 'Typette',
color: Colors.brown.shade100,
fontSize: 30.sp,
fontWeight: FontWeight.w400
),
),
Text('STARBUCKS',
style: TextStyle(
fontFamily: 'Typette',
color: Colors.brown.shade50,
fontSize: 30.sp,
fontWeight: FontWeight.w400
),
),
],
),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SizeAndFave(text: 'Preference'),
SizeAndFave(text: 'Fave!')
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: (){
setState(() {
_flag = !_flag;
});
},
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
transitionBuilder: (Widget child, Animation<double> animation){
return FadeTransition(opacity: animation, child: child,);
},
child: widget.rep == true?Padding(
padding: const EdgeInsets.all(14.0),
key: const Key('1'),
child: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
border: Border.all(
color: Colors.brown.shade300,
width: 3
),
borderRadius: BorderRadius.circular(10)
),
child: const Center(
child: Icon(
Icons.coffee_outlined,
size: 20,
),
)
),
):null,
)
),
GestureDetector(
onTap: (){
setState(() {
_favourite = !_favourite;
});
},
child: _favourite? TopIcon(icons: Icons.favorite_border, color: Colors.brown.shade300)
:TopIcon(
icons: Icons.favorite, color: Colors.brown.shade300)
)
],
)
],
),
AnimatedSwitcher(
duration: Duration(seconds: 1),
transitionBuilder: (Widget child, Animation<double> animation) {
return FadeTransition( opacity: animation,
child: child);
},
child: _flag == true ? Center(
key: const Key('1'),
child: SlideTransition(
position: widget.animation,
child: SizedBox(
height: 80.h,
width: 80.w,
child: Image.asset('assets/images/starcup.png'),
),
),
):Center(
key: const Key('2'),
child: SlideTransition(
position: widget.animation,
child: SizedBox(
height: 80.h,
width: 80.w,
child: Image.asset('assets/images/greeen.png'),
),
),
),
),
Positioned(
child:
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(top: 30.h),
child: TopIcon(
icons: Icons.car_crash_outlined, color: Colors.brown.shade300),
),
)),
const Positioned(
child:
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: EdgeInsets.only(top: 330.0, left: 14),
child: Text('\$ 5.99',
style: TextStyle(
fontSize: 27,
fontWeight: FontWeight.bold
),
),
),
))
],
),
);
}
}
and lastly, the lower area
class LowerArea extends StatefulWidget {
final AnimationController controller;
final Animation<Offset> anime;
bool rep;
LowerArea({Key? key, required this.controller, required this.anime, required this.rep}) : super(key: key);
#override
State<LowerArea> createState() => _LowerAreaState();
}
class _LowerAreaState extends State<LowerArea> {
bool _bigger = true;
bool _fade = true;
void move(){
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: EdgeInsets.all(1.h),
child: const Text('Tall Frappuccino',
style: TextStyle(
fontWeight: FontWeight.w500
),
),
),
Padding(
padding: EdgeInsets.only(right: 5.h),
child: const Text('Swipe Down',
style: TextStyle(
fontWeight: FontWeight.w500
),
),
),
Padding(
padding: EdgeInsets.all(2.h),
child: const Text('Pickup',
style: TextStyle(
fontWeight: FontWeight.w500
),
),
)
],
),
),
SlideTransition(
position: widget.anime,
child: AnimatedContainer(
// height: 11.h,
width: _bigger ? 35.h: 80.h,
duration: const Duration(milliseconds: 500),
child: Stack(
fit: StackFit.loose,
children: [
Center(child: Image.asset('assets/images/baggie.png')),
Center(
child: Padding(
padding: EdgeInsets.only(bottom: 4.h),
child: GestureDetector(
onTap: (){
widget.controller.forward();
setState(() {
_bigger = !_bigger;
_fade = !_fade;
widget.rep = !widget.rep;
print('this is fade $_fade ');
});
},
child: AnimatedSwitcher(
duration: Duration(milliseconds: 300),
transitionBuilder: (Widget child, Animation<double> animation){
return FadeTransition(opacity: animation, child: child,);
},
child: _fade? Container(
key: Key('1'),
height: 8.h,
width: 7.w,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(15)
),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(0.3.h),
child: Icon(
Icons.lock_outline,
color: Colors.white54,
size: 2.5.h,
),
),
Icon(
Icons.arrow_drop_down,
color: Colors.white12,
size: 3.h,
),
],
),
):null,
),
),
),
)
],
),
),
)
],
);
}
use provider pacakges https://pub.dev/packages/provider
Create a class that inherits the functions of ChangeNotifyer to create a flag to control and create a setter.
provider class
class StateController extends ChangeNotifier{
bool _req = false;
bool get req => _req; //getter
setReqValue(){
_req = !_req;
notifyListener();
}
}
Declare the provider class in the main function. You can change the location of the declaration according to Wiget tree, but first declare it in main
Change main.dart
void main(){
runApp(
Multiprovider(
providers: [
ChangeNotifierProvider(create: (_) => StateController()),
],
child: HomePage(),
)
);
}
The UI is updated by notifyListener().
change UI
child: context.watch<StateController>().req == true ? Padding(
padding: const EdgeInsets.all(14.0),
key: const Key('1'),
child: Container(
height: 40,
width: 40,
decoration: BoxDecoration(
border: Border.all(
color: Colors.brown.shade300,
width: 3
),
borderRadius: BorderRadius.circular(10)
),
child: const Center(
child: Icon(
Icons.coffee_outlined,
size: 20,
),
)
),
):null,
Change State
onTap: (){
widget.controller.forward();
setState(() {
_bigger = !_bigger;
_fade = !_fade;
context.read<StateController>().setReqValue();
print('this is fade $_fade ');
});
},
I am too lazy to try understand your code. But if you want to update state of the page after you pop from Navigation to it.
In page you want to update
Navigation.push(context, /* Page that will change something */)
// Future will trigger then you return to this page.
.then((_) => setState(() {}))
Hey guys I'm working on some project and need to create a custom dropdown,
like this
I am able to make that here is the code, the code is messy but I will refactor it once I make it work. Or if you have some other way how I can accomplish this I'm open to suggestions.
GlobalKey? actionKey = GlobalKey();
List<String> picked = [];
List<IconData> icons = [
Icons.blur_circular_outlined,
Icons.sports_basketball,
Icons.sports_baseball_sharp,
Icons.sports_tennis_rounded,
Icons.people,
];
List<String> sports = [
"Fudbal",
"Kosarka",
"Tenis",
"Stoni tenis",
"Kuglanje"
];
List<int> ints = [0, 1, 2, 3, 4];
List<bool> booles = [false, false, false, false, false];
OverlayEntry? overlayEntry;
var position;
double? y;
double? x;
void findDropdownData() {
RenderBox renderBox =
actionKey!.currentContext!.findRenderObject() as RenderBox;
position = renderBox.localToGlobal(Offset.zero);
y = position!.dy;
x = position!.dx;
}
OverlayEntry _overlayEntryBuilder() {
return OverlayEntry(
builder: (context) {
return Positioned(
// top: position,
left: 16.w,
right: 16.w,
child: Material(
child: dropdownExpanded(),
),
);
},
);
}
Widget buildRows(i) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 17.w, vertical: 15.h),
child: Row(
children: [
SizedBox(
height: 24.h,
width: 24.w,
child: Checkbox(
activeColor: style.purpleMain,
value: booles[i],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
onChanged: (value) {
setState(() {
booles[i] = value!;
booles[i] == true
? picked.add(sports[i])
: picked.remove(sports[i]);
});
},
),
),
SizedBox(
width: 10.w,
),
Text(
sports[i],
style: TextStyle(
color: booles[i] == true ? style.purpleMain : Colors.grey,
),
),
const Spacer(),
Icon(
icons[i],
color: booles[i] == true ? style.purpleMain : Colors.grey,
size: 15,
),
],
),
);
}
Widget dropdown() {
return GestureDetector(
key: actionKey,
onTap: () {
setState(() {
isPressed = !isPressed;
});
if (isPressed == false) {
overlayEntry = _overlayEntryBuilder();
Overlay.of(context)!.insert(overlayEntry!);
}
},
child: Container(
width: double.infinity,
height: 50.h,
decoration: BoxDecoration(
border: Border.all(color: style.e8e8e8),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.only(left: 16.w, right: 13.w),
child: Row(
children: [
picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
const Spacer(),
const Icon(
Icons.arrow_drop_down,
color: style.bdbdbd,
),
],
),
),
);
}
Widget pickedEmpty() {
return Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(
fontSize: 16.sp,
color: style.bdbdbd,
fontWeight: FontWeight.w400,
),
);
}
Widget pickedNotEmpty() {
List<Widget> list = <Widget>[];
for (var i = 0; i < picked.length; i++) {
list.add(
Padding(
padding: EdgeInsets.only(right: 5.w),
child: Text(
picked[i],
style: TextStyle(
fontSize: 16.sp,
color: style.bdbdbd,
fontWeight: FontWeight.w400,
),
),
),
);
}
return Row(children: list);
}
Widget dropdownExpanded() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: style.purpleMain),
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
GestureDetector(
onTap: () {
setState(() {
isPressed = !isPressed;
});
overlayEntry?.remove();
},
child: Container(
width: double.infinity,
height: 50.h,
padding: EdgeInsets.only(left: 16.w, right: 13.w),
child: Row(
children: [
picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
const Spacer(),
const Icon(
Icons.arrow_drop_up,
color: style.bdbdbd,
),
],
),
),
),
const Divider(
height: 0,
thickness: 1,
color: style.e8e8e8,
indent: 17,
endIndent: 17,
),
Column(
children: [
for (int i in ints) buildRows(i),
],
),
],
),
);
}
Here are results
This is what I want to accomplish
So I just want to move down this expanded dropdown and how to update these booles in the overlay if I don't use overlay it's working as it should but I need to open that dropdown on the top of another content. Thanks for the help.
Use smart_select it is fully customizable and you can achieve the design you want easily using this library.
Updated Answer
Regarding the UI, it is like an Expansions Tile Widget in flutter. You can implement that dropdown with expansions tile and pass list of items in children,
for expand, collapse tile after select each item, you can create a global key and control that in UI.
final GlobalKey<AppExpansionTileState> expansionTile = new GlobalKey();
collapse → expansionTile.currentState.collapse();
ExpansionTile(
title: Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
),
children: <Widget>[
// put items here
],
),
smaple :
Widget customDropDown() => Container(
// color: Colors.white,
padding: const EdgeInsets.all(10),
child: ListTileTheme(
dense: true,
child: ExpansionTile(
title: const Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
),
children: <Widget>[
Container(
width: double.infinity,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.vertical(bottom: Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: const [
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
)
],
),
),
)
],
),
),
);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: Stack(
children: [pageDesign(), customDropDown()],
),
),
),
);
}
fakeWidget(color) => Container(
height: 100,
width: double.infinity,
color: color,
child: const Center(
child: Text("widget1"),
),
);
Widget pageDesign() => Column(
children: [
/* you should control this size in diffrent orientation and for big size
device to handle responsive
*/
const SizedBox(
height: 80,
),
fakeWidget(
Colors.green,
),
fakeWidget(
Colors.yellow,
),
fakeWidget(
Colors.orange,
),
fakeWidget(
Colors.blue,
),
],
);
I am currently working on the ui stuff for the appliction, so the thing is i have one gesture as a parent that swipes up and down and based on it the position of the widgets gets changed but the problem is the child gesture does not get any precedence when tapped on it it gives the precedence. So my tree structure is Pageview.builder which has single widget with topmost parent as Gesturedetector and the children accrodingly, Can any one tell me what i am doing wrong or any improvements to get the gesture for each.
Below is the sample code that i have been working on:
import 'dart:math';
import 'package:LocationAnimation/Model/device_model.dart';
import 'package:LocationAnimation/SplashPage/splash_page.dart';
import 'package:LocationAnimation/widgets/device_function_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:google_fonts/google_fonts.dart';
import 'Model/device_model.dart' as devices;
import 'Model/locations_model.dart' as locations;
import 'extensions/capitalize.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'HAL',
home: MyHomePage(),
);
}
}
class SampleList {
final String locationName;
SampleList({this.locationName});
}
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
final _controller = new PageController();
final _kArrowColor = Colors.black.withOpacity(0.8);
bool _isSwipe = false;
bool _isLoading = false;
var list = [
SampleList(locationName: 'Living Room'),
SampleList(locationName: 'Bed Room'),
SampleList(locationName: 'Back Porch Lights'),
SampleList(locationName: 'Basement Porch Lights'),
SampleList(locationName: 'Sample Room'),
];
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new IconTheme(
data: new IconThemeData(color: _kArrowColor),
child: new Stack(
children: <Widget>[
new PageView.builder(
physics: _isSwipe
? NeverScrollableScrollPhysics()
: AlwaysScrollableScrollPhysics(),
controller: _controller,
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return LocationDetails(
isLoading: _isLoading,
item: list[index],
onSwipeDown: () {
setState(() {
_isSwipe = false;
});
},
onSwipeUp: () {
setState(() {
_isSwipe = true;
});
},
);
},
),
],
),
),
);
}
}
class LocationDetails extends StatefulWidget {
final bool isLoading;
SampleList item;
final Function() onSwipeUp;
final Function() onSwipeDown;
LocationDetails(
{Key key, this.item, this.onSwipeUp, this.onSwipeDown, this.isLoading})
: super(key: key);
#override
_LocationDetailsState createState() => _LocationDetailsState();
}
class _LocationDetailsState extends State<LocationDetails> {
DragStartDetails startVerticalDragDetails;
DragUpdateDetails updateVerticalDragDetails;
bool moveWidget = false;
bool dismissSwipeText = true;
bool _isRotate = false;
int currentSelectedIndex = 0;
bool ignoreChildGestures = true;
bool _isSwpie = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
child: GestureDetector(
onTap: () {
print('Tap');
},
onVerticalDragStart: (dragDetails) {
startVerticalDragDetails = dragDetails;
},
onVerticalDragUpdate: (dragDetails) {
updateVerticalDragDetails = dragDetails;
},
onVerticalDragEnd: (endDetails) {
double dx = updateVerticalDragDetails.globalPosition.dx -
startVerticalDragDetails.globalPosition.dx;
double dy = updateVerticalDragDetails.globalPosition.dy -
startVerticalDragDetails.globalPosition.dy;
double velocity = endDetails.primaryVelocity;
//Convert values to be positive
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
if (velocity < 0) {
widget.onSwipeUp();
print('drag up');
setState(() {
moveWidget = true;
_isSwpie = true;
});
} else {
widget.onSwipeDown();
print(' drag down');
setState(() {
moveWidget = false;
_isSwpie = false;
});
}
},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
image: new DecorationImage(
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(0.8), BlendMode.srcOver),
image: /* moveWidget
? */
AssetImage(
'Assets/backgroundImage.jpg',
),
/* : NetworkImage(widget.samplePage.networkImage), */
fit: BoxFit.fill,
),
),
child:
/* widget.isLoading
? Center(
child: CircularProgressIndicator(),
)
: */
Stack(
children: <Widget>[
AnimatedOpacity(
opacity: moveWidget ? 0 : 1,
duration: Duration(microseconds: 100),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
children: <Widget>[
Icon(
Icons.power_settings_new,
color: Colors.white,
size: 30,
),
Icon(
Icons.more_horiz,
color: Colors.white,
size: 25,
)
],
),
Row(
children: <Widget>[
Column(
children: <Widget>[
Text(
'Inside Temp',
style: TextStyle(
color: Colors.white, fontSize: 18),
),
SizedBox(
height: 5,
),
Row(
children: <Widget>[
Icon(
Icons.ac_unit,
color: Colors.white,
size: 20,
),
SizedBox(
width: 10,
),
Text(
'19 C',
style: TextStyle(color: Colors.white),
),
],
)
],
),
SizedBox(
width: 10,
),
Column(
children: <Widget>[
Text(
'Outside Temp',
style: TextStyle(
color: Colors.white, fontSize: 18),
),
SizedBox(
height: 5,
),
Row(
children: <Widget>[
Icon(
Icons.ac_unit,
color: Colors.white,
size: 20,
),
SizedBox(
width: 10,
),
Text(
'19 C',
style: TextStyle(color: Colors.white),
),
],
)
],
),
],
)
],
),
),
),
AnimatedPositioned(
onEnd: () {
setState(() {
dismissSwipeText = !dismissSwipeText;
//print(dismissSwipeText);
});
},
curve: Curves.ease,
duration: Duration(milliseconds: 700),
bottom: moveWidget
? 10
: MediaQuery.of(context).size.height * 0.18,
left: 10.0,
right: 0.0,
top: moveWidget
? 50
: MediaQuery.of(context).size.height * 0.75,
child: AnimatedOpacity(
opacity: dismissSwipeText ? 1 : 0,
duration: Duration(milliseconds: 500),
child: Text(
'Swipe up to customize',
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
AnimatedPositioned(
curve: Curves.ease,
duration: Duration(milliseconds: 700),
onEnd: () {
setState(() {
_isSwpie = true;
});
},
left: 10,
top: moveWidget
? 80
: MediaQuery.of(context).size.height * 0.80,
child: Container(
width: MediaQuery.of(context).size.width * 0.97,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
currentSelectedIndex = 0;
});
},
child: Container(
width: MediaQuery.of(context).size.width * 0.20,
height:
MediaQuery.of(context).size.height * 0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: currentSelectedIndex == 0
? Colors.blue
: Colors.grey[900],
),
child: Center(
child: Text(
'Lights',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
),
Row(
children: <Widget>[
SizedBox(
width: 10,
),
GestureDetector(
onTap: () {
setState(() {
currentSelectedIndex = 1;
});
},
child: Container(
width: MediaQuery.of(context).size.width *
0.20,
height: MediaQuery.of(context).size.height *
0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: currentSelectedIndex == 1
? Colors.blue
: Colors.grey[900],
),
child: Center(
child: Text(
'Applicanes',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
),
],
),
Row(
children: <Widget>[
SizedBox(
width: 10,
),
GestureDetector(
onTap: () {
setState(() {
currentSelectedIndex = 2;
});
},
child: Container(
width: MediaQuery.of(context).size.width *
0.20,
height: MediaQuery.of(context).size.height *
0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: currentSelectedIndex == 2
? Colors.blue
: Colors.grey[900],
),
child: Center(
child: Text(
'Sensors',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
),
],
),
Row(
children: <Widget>[
SizedBox(
width: 10,
),
Container(
width:
MediaQuery.of(context).size.width * 0.20,
height:
MediaQuery.of(context).size.height * 0.10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[900],
),
child: Center(
child: Text(
'Doors \n& Locks',
style: GoogleFonts.lato(
color: Colors.white,
fontWeight: FontWeight.w700),
)),
),
],
),
SizedBox(
width: 10,
),
],
),
),
),
AnimatedPositioned(
curve: Curves.ease,
duration: Duration(milliseconds: 400),
bottom: moveWidget
? 10
: MediaQuery.of(context).size.height * 0.20,
left: 10.0,
right: 0.0,
top: moveWidget
? 15
: MediaQuery.of(context).size.height * 0.70,
child: Text(
'${widget.item.locationName}',
style: TextStyle(fontSize: 30, color: Colors.white),
),
),
],
)),
),
),
),
);
}
}
You can add Color to the last AnimatedPositioned which use text widget.item.locationName in your code, like:
AnimatedPositioned(
curve: Curves.ease,
duration: Duration(milliseconds: 400),
bottom: moveWidget
? 10
: MediaQuery.of(context).size.height * 0.20,
left: 10.0,
right: 0.0,
top: moveWidget
? 15
: MediaQuery.of(context).size.height * 0.70,
child: Container(
color: Colors.white,
Text(
'${widget.item.locationName}',
style: TextStyle(fontSize: 30, color: Colors.white),
),
),
),
You will see a white screen (the widget which blocking you) when you scroll up. You can fix it by 2 ways
Change the bottom 10 to a larger number
Move this part of AnimatedPositioned to Top of the Stack widget
The Nested Gesture should work probably as you expected.
First of All you are using multiple Scaffold in a single page which is not recommended.
And remove the unwanted widgets from your tree which will help you to debug a way more better level. And Next you can try with passing a Callback function from parent to child which can eventually solve your problem
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),
),
);
}
}