Flutter GridView Item Selection Color Change (on tap) - flutter

I have created a GridView, and the next step I'm trying to achieve is changing the color of the container when it is tapped/ selected. When I try and do it with both Inkwell and GestureDetector, it changes the color of both containers in the row, rather than changing each one individually. I want to have each container change colors when it is tapped, as well as have a check mark appear on the corner:
(1) My Layout
(2) Example of what I want
I'm very new to Flutter, so I know that the way that I've coded my layout is far from optimal. I'm attaching a small chunk of just the GridView portion to show how I created the GridView (basically, I created 6 containers all with varying custom icons and text). Hopefully I'll receive some assistance :).
Updated June 21st:
class SelectionPage extends StatefulWidget {
const SelectionPage({Key? key}) : super(key: key);
#override
_SelectionPageState createState() => _SelectionPageState();
}
class Item{
String title;
bool isSelected;
Item({required this.title, this.isSelected = false});
List <Item>listOfModel = [];
listOfModel.add(Item(title: "Maintaining healthy relationships"));
listOfModel.add(Item(title: "Being happier and more content in life"));
}
class _SelectionPageState extends State<SelectionPage>{
Color _ContainerColor = Colors.white;
#override
Widget build(BuildContext) {
double _height = MediaQuery.of(context).size.height;
final data = ModalRoute.of(context)!.settings;
late String retrieveString;
if (data.arguments == null)
retrieveString = "empty";
else
retrieveString = data.arguments as String;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
body: Padding(
padding: EdgeInsets.only(
left: 30,
right: 30,
top: _height * 0.2),
child: Column(
children: <Widget>[
Text('Hello there $data! What all would you like to focus on? You can pick all that apply:',
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 19,
fontWeight: FontWeight.w600
),
textAlign: TextAlign.center,),
const SizedBox(height: 12,),
Column(children: [
GridView.count(
primary: true,
shrinkWrap: true,
padding: const EdgeInsets.all(10),
childAspectRatio: 1.15,
crossAxisCount: 2,
crossAxisSpacing: 25,
mainAxisSpacing: 25,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
_ContainerColor = _ContainerColor == Colors.white
? Color(0xffa1d0e6)
: Colors.white;
});
},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: _ContainerColor
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp.relationships,
color: Color(0xff31708c),
size: 45,),
),
const SizedBox(height: 4,),
Text('Maintaining healthy relationships',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
),
GestureDetector(
onTap: () {
setState(() {
_ContainerColor = _ContainerColor == Colors.white
? Color(0xffa1d0e6)
: Colors.white;
});
},
child: Container(
padding: const EdgeInsets.all(13.5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp.happy,
color: Color(0xff31708c),
size: 30,),
),
const SizedBox(height: 12,),
Text('Being happier and more content in life',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp.balance,
color: Color(0xff31708c),
size: 40,),
),
const SizedBox(height: 8,),
Text('Maintaining a better work-life balance',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp2.personal_growth,
color: Color(0xff31708c),
size: 35,),
),
const SizedBox(height: 10,),
Text('Personal growth and development',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp2.meditate,
color: Color(0xff31708c),
size: 45,),
),
const SizedBox(height: 4,),
Text('Stress and anxiety management',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
Container(
padding: const EdgeInsets.all(11),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp3.well_rounded,
color: Color(0xff31708c),
size: 37,),
),
const SizedBox(height: 10,),
Text('Mental and emotional well-being',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
],
),]),
const SizedBox(height: 17,),
ElevatedButton(
onPressed: () {
Navigator.push(context,
PageTransition(
type: PageTransitionType.bottomToTop,
duration: const Duration(milliseconds: 650),
child: const LoginScreen2() // CHANGE THIS AS SOON AS YOU CAN FIGURE SOMETHING OUT
));
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 88,
vertical: 16),
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
)
),
child: Text(
'Continue',
style: GoogleFonts.montserrat(
color: const Color.fromARGB(255, 20, 83, 106),
fontSize: 19,
fontWeight: FontWeight.w600
),
),)
],
),
),
);
}
}

Hey you can create a model with 2 variables String title and bool isSelected. If you need you can add icon in item model also -
See below updated code-
class SelectionPage extends StatefulWidget {
const SelectionPage({Key? key}) : super(key: key);
#override
_SelectionPageState createState() => _SelectionPageState();
}
class _SelectionPageState extends State<SelectionPage>{
// Color _ContainerColor = Colors.white;
late String retrieveString;
List <Item>listOfModel = [];
#override
void initState() {
final data = ModalRoute.of(context)!.settings;
if (data.arguments == null) {
retrieveString = "empty";
} else {
retrieveString = data.arguments as String;
}
listOfModel.add(Item(title: "Maintaining healthy relationships"));
listOfModel.add(Item(title: "Being happier and more content in life"));
super.initState();
}
#override
Widget build(BuildContext context) {
double _height = MediaQuery.of(context).size.height;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
body: Padding(
padding: EdgeInsets.only(
left: 30,
right: 30,
top: _height * 0.2),
child: Column(
children: <Widget>[
Text('Hello there $data! What all would you like to focus on? You can pick all that apply:',
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 19,
fontWeight: FontWeight.w600
),
textAlign: TextAlign.center,),
const SizedBox(height: 12,),
GridView.count(
primary: true,
shrinkWrap: true,
padding: const EdgeInsets.all(10),
childAspectRatio: 1.15,
crossAxisCount: 2,
crossAxisSpacing: 25,
mainAxisSpacing: 25,
children: [
gridItem(listOfModel[0],MyFlutterApp.relationships ),
gridItem(listOfModel[1],MyFlutterApp.relationships ),
],
),
const SizedBox(height: 17,),
ElevatedButton(
onPressed: () {
Navigator.push(context,
PageTransition(
type: PageTransitionType.bottomToTop,
duration: const Duration(milliseconds: 650),
child: const LoginScreen2() // CHANGE THIS AS SOON AS YOU CAN FIGURE SOMETHING OUT
));
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 88,
vertical: 16),
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
)
),
child: Text(
'Continue',
style: GoogleFonts.montserrat(
color: const Color.fromARGB(255, 20, 83, 106),
fontSize: 19,
fontWeight: FontWeight.w600
),
),)
],
),
),
);
}
Widget gridItem(Item item, IconData icon){
return GestureDetector(
onTap: () {
setState(() {
item.isSelected = !item.isSelected;
});
},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: item.isSelected ? const Color(0xffa1d0e6) : Colors.white
),
child: Column(
children: [
Align(alignment: Alignment.topCenter,
child: Icon(
icon,
color: const Color(0xff31708c),
size: 45,
),
),
const SizedBox(height: 4,),
Text(item.title,
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
);
}
}
class Item{
String title;
bool isSelected;
Item({required this.title, this.isSelected = false});
}

Related

Execute animation when button clicked flutter

I am creating a flutter web where is created home and about widget in column and uses SlideTransition on about widget but the thing is when the page load the animation happen even I am on Home widget.
I want when i click on about widget then the animation will occur not at the start of page.
how to do that?
Here is my code:
class MainPage extends StatefulWidget {
const MainPage({super.key});
#override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> with TickerProviderStateMixin {
bool aboutClick = false;
bool servicesClick = false;
bool contactClick = false;
final fname = TextEditingController();
final lname = TextEditingController();
final email = TextEditingController();
final phoneNo = TextEditingController();
final message = TextEditingController();
final emailVerificationSyntax = RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+");
final homeKey = GlobalKey();
final aboutKey = GlobalKey();
final servicesKey = GlobalKey();
final contactKey = GlobalKey();
AnimationController? animationController;
Animation<Offset>? _animationValue;
#override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..forward();
_animationValue = Tween<Offset>(
begin: const Offset(-0.5, 0.0), end: const Offset(0.0, 0.0))
.animate(
CurvedAnimation(
parent: animationController!,
curve: Curves.easeIn,
),
);
// animationController!.addStatusListener((status) {
// if (status == AnimationStatus.completed) {
// animationController!.reverse();
// } else if (status == AnimationStatus.dismissed) {
// animationController!.forward();
// }
// });
// animationController!.forward();
}
#override
void dispose() {
animationController!.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MediaQuery.of(context).size.width <= 910
? const MobileMainPage()
: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
toolbarHeight: 100,
flexibleSpace: Container(
color: Colors.black,
width: double.infinity,
height: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RichText(
textScaleFactor: 1.3,
text: const TextSpan(
style: TextStyle(
color: Colors.black,
fontSize: 25,
),
children: <TextSpan>[
TextSpan(
text: "Rizwan",
style: TextStyle(
color: Colors.white,
fontSize: 40,
fontWeight: FontWeight.bold,
fontFamily: "Joining",
),
),
TextSpan(
text: " •",
style: TextStyle(
fontSize: 50,
color: Colors.green,
fontWeight: FontWeight.bold,
fontFamily: "Joining",
),
),
],
),
),
Row(
children: [
TextButton(
onPressed: () {
Scrollable.ensureVisible(homeKey.currentContext!,
duration: const Duration(seconds: 2),
curve: Curves.ease);
},
style: TextButton.styleFrom().copyWith(
animationDuration:
const Duration(milliseconds: 300),
textStyle: MaterialStateProperty.resolveWith(
(states) {
if (states.contains(MaterialState.hovered)) {
return const TextStyle(
fontSize: 35,
);
}
return const TextStyle(
fontSize: 30,
);
},
),
foregroundColor:
MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.hovered)) {
return Colors.green;
}
return Colors.white;
})),
child: const Text(
"Home",
style: TextStyle(
fontFamily: "Simple",
),
),
),
const SizedBox(
width: 10,
),
TextButton(
onPressed: () {
Scrollable.ensureVisible(aboutKey.currentContext!,
duration: const Duration(seconds: 2),
curve: Curves.ease);
setState(() {
aboutClick = true;
});
},
style: TextButton.styleFrom().copyWith(
animationDuration:
const Duration(milliseconds: 300),
textStyle: MaterialStateProperty.resolveWith(
(states) {
if (states.contains(MaterialState.hovered)) {
return const TextStyle(
fontSize: 35,
);
}
return const TextStyle(
fontSize: 30,
);
},
),
foregroundColor:
MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.hovered)) {
return Colors.green;
}
return Colors.white;
})),
child: const Text(
"About",
style: TextStyle(
fontFamily: "Simple",
),
),
),
],
),
],
),
),
),
body: SingleChildScrollView(
child: Column(
children: [
homeWidget(homeKey),
aboutWidget(aboutKey, _animationValue),
servicesWidget(servicesKey),
contactWidget(contactKey, fname, lname, email, phoneNo,
message, emailVerificationSyntax)
],
),
),
);
}
homeWidget(GlobalKey<State<StatefulWidget>> homeKey) {
return Row(
key: homeKey,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 160,
),
const Text(
"Hi, I am",
style: TextStyle(
color: Colors.white,
fontSize: 60,
fontWeight: FontWeight.bold),
),
const SizedBox(
height: 10,
),
const Text(
"RIZWAN ALI",
style: TextStyle(
color: Colors.white,
fontSize: 70,
fontWeight: FontWeight.bold,
fontFamily: "Shade",
),
),
const SizedBox(
height: 10,
),
DefaultTextStyle(
style: const TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.bold,
color: Colors.grey),
child: AnimatedTextKit(
pause: const Duration(seconds: 1),
repeatForever: true,
animatedTexts: [
TypewriterAnimatedText(
'Flutter Developer',
speed: const Duration(
milliseconds: 90,
),
curve: Curves.linear,
),
TypewriterAnimatedText(
'Android Native Developer',
speed: const Duration(
milliseconds: 90,
),
curve: Curves.linear,
),
TypewriterAnimatedText(
'Web Developer',
speed: const Duration(
milliseconds: 90,
),
curve: Curves.linear,
),
TypewriterAnimatedText(
'Freelancer',
speed: const Duration(
milliseconds: 90,
),
curve: Curves.linear,
),
TypewriterAnimatedText(
'Photographer',
speed: const Duration(
milliseconds: 90,
),
curve: Curves.linear,
),
TypewriterAnimatedText(
'Cricketer',
speed: const Duration(
milliseconds: 90,
),
curve: Curves.linear,
),
],
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(20),
shape: const StadiumBorder(),
backgroundColor: Colors.green,
),
child: const Text(
"Download CV",
style: TextStyle(
fontSize: 40,
),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 70.0),
child: Container(
width: 450,
height: 450,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("me.jpg"),
fit: BoxFit.cover,
),
shape: BoxShape.circle,
),
),
),
],
);
}
aboutWidget(GlobalKey<State<StatefulWidget>> aboutKey,
Animation<Offset>? animationValue) {
return SlideTransition(
position: animationValue!,
child: Padding(
key: aboutKey,
padding: const EdgeInsets.only(top: 80.0),
child: SizedBox(
height: 600,
width: double.infinity,
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
"ABOUT",
style: TextStyle(
color: Colors.white,
fontSize: 35,
fontWeight: FontWeight.bold,
fontFamily: "Simple",
),
),
const SizedBox(
height: 20,
),
SizedBox(
width: 700,
height: 100,
child: Wrap(
children: const [
Text(
"I'm a Flutter and Android Native Developer building Applications that leads to the success of the overall product. Check out some of my work in the Work section. I also like sharing content related to the stuff that I have learned in Flutter Development so it can help other people of the Dev Community. Feel free to Connect or Follow me on my Linkedin where I post useful content related to Web Development and Programming. I'm open to Job opportunities where I can contribute, learn and grow. If you have a good opportunity that matches my skills and experience then don't hesitate to contact me.",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
textAlign: TextAlign.center,
)
],
),
),
const SizedBox(
height: 120,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 40,
height: 40,
decoration: const BoxDecoration(
color: Color.fromARGB(221, 49, 40, 40),
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: Center(
child: Container(
width: 15,
height: 15,
decoration: const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
),
),
),
const SizedBox(
width: 200,
),
Container(
width: 40,
height: 40,
decoration: const BoxDecoration(
color: Color.fromARGB(221, 49, 40, 40),
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: Center(
child: Container(
width: 15,
height: 15,
decoration: const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
),
),
),
const SizedBox(
width: 200,
),
Container(
width: 40,
height: 40,
decoration: const BoxDecoration(
color: Color.fromARGB(221, 49, 40, 40),
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: Center(
child: Container(
width: 15,
height: 15,
decoration: const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
),
),
),
const SizedBox(
width: 200,
),
Container(
width: 40,
height: 40,
decoration: const BoxDecoration(
color: Color.fromARGB(221, 49, 40, 40),
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: Center(
child: Container(
width: 15,
height: 15,
decoration: const BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
),
),
),
],
),
const SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"Name",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
),
SizedBox(
width: 200,
),
Text(
"Email",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
),
SizedBox(
width: 180,
),
Text(
"Linkedin",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
),
SizedBox(
width: 180,
),
Text(
"Phone",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
),
],
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
width: 20,
),
const Text(
"RIZWAN ALI",
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
const SizedBox(
width: 90,
),
const Text(
"rizwanali96960#gmail.com",
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
const SizedBox(
width: 50,
),
TextButton(
onPressed: () async {
final url = Uri.parse(
"https://www.linkedin.com/in/rizwan-ali-361514212");
if (await canLaunchUrl(url)) {
await launchUrl(
url,
);
}
},
child: const Text(
"Linkedin-Profile",
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
),
const SizedBox(
width: 90,
),
const Text(
"+92 307 4500296",
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
],
),
const SizedBox(
height: 45,
),
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(15),
shape: const StadiumBorder(),
backgroundColor: Colors.green,
),
child: const Text(
"LET'S TALK",
style: TextStyle(
fontSize: 35,
),
),
),
],
),
),
),
),
);
}
You should not start the animation during initState, if you don't want the animation to play right away.
In your code:
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..forward(); // <----- REMOVE THIS PART
In your code above, you should remove the ..forward() during the initialization. This will prevent it to run at the start of the page.
Next, in the button click event, you can call animationController.forward() and it should begin the animation. You can also specify a starting point, e.g. animationController.forward(from: 0), to ensure the animation always starts at the very beginning.

Container inside Material widget taking full screen height in flutter

I am trying to implement a card-like overlay whose height will be dependent on the child texts.
This is the code of my flutter card overlay which is taking full-screen height. How should I fix it without declaring a constant height as the amount of text is variable.
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_overlay_window/flutter_overlay_window.dart';
class TrueCallerOverlay extends StatefulWidget {
const TrueCallerOverlay({Key? key}) : super(key: key);
#override
State<TrueCallerOverlay> createState() => _TrueCallerOverlayState();
}
class _TrueCallerOverlayState extends State<TrueCallerOverlay> {
bool isGold = true;
final _goldColors = const [
Color.fromARGB(255, 51, 219, 79),
Color.fromARGB(255, 151, 235, 169),
Color.fromARGB(255, 15, 107, 35),
];
final _silverColors = const [
Color(0xFFAEB2B8),
Color(0xFFC7C9CB),
Color(0xFFD7D7D8),
Color(0xFF003226),
];
final bgColor = Color(0xFF003226);
final textColor = Colors.white;
#override
void initState() {
super.initState();
FlutterOverlayWindow.overlayListener.listen((event) {
log("$event");
setState(() {
isGold = !isGold;
});
});
}
#override
Widget build(BuildContext context) {
return Material(
color: Colors.transparent,
child: Center(
child: Container(
padding: const EdgeInsets.symmetric(vertical: 12.0),
width: double.infinity,
//height: double.infinity,
decoration: BoxDecoration(
color: bgColor,
// gradient: LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: isGold ? _goldColors : _silverColors,
// ),
borderRadius: BorderRadius.circular(12.0),
),
child: GestureDetector(
onTap: () {
FlutterOverlayWindow.shareData(
"Heyy this is a data from the overlay");
},
child: Stack(
children: [
Center(
child: Column(
children: [
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
"Attention",
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 28,
color: textColor),
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
"t1",
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: 20,
color: textColor),
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
"t2",
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: 20,
color: textColor),
),
),
Container(
alignment: Alignment.centerRight,
margin: EdgeInsets.all(25),
child: FlatButton(
child: Text(
'Reference',
style: TextStyle(fontSize: 20.0),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {},
),
),
],
),
),
Positioned(
top: 0,
right: 0,
child: IconButton(
onPressed: () async {
await FlutterOverlayWindow.closeOverlay();
},
icon: const Icon(
Icons.close,
color: Colors.white,
),
),
),
],
),
),
),
),
);
}
}
this is the current output What I am expecting
just wrap your Container with IntrinsicHeight or SingleChildScrollView.

How to have custom color and border if selected

I wanted to implement a theme picker in my app so I made a dialog and got the title of the theme and the index with which it's going to be chosen class... now I want the dialog to show a border around the selected theme and show the background color of each theme
this is the code I use for the class:
class MultiThemeModel {
int index;
String themeName;
MultiThemeModel({required this.index, required this.themeName});
}
titlesForThemeModel(int index) {
switch (index) {
case 0:
return 'Luxury Purple';
case 1:
return 'Red Wine';
}
return 'No theme for index';
}
List<MultiThemeModel> get themes => List<MultiThemeModel>.generate(
2,
(index) =>
MultiThemeModel(index: index, themeName: titlesForThemeModel(index)));
List<Widget> get widgets => themes
.map((themeData) => MultipleThemeViewerWidget(themeData: themeData))
.toList();
what do I need to do to implement the features described above? I thought about maybe having a boolean and a color property in the class but I don't know how to map it and get it into the list... would be great to get some advice
thanks for the help in advance:)
Edit:
this is the Container for the colors:
class MultipleThemeViewerWidget extends StatelessWidget {
MultipleThemeViewerWidget({Key? key, required this.themeData})
: super(key: key);
final MultiThemeModel themeData;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
getThemeManager(context).selectThemeAtIndex(themeData.index);
},
child: Container(
height: 60,
width: 105,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(.3),
border: Border.all(
color: Theme.of(context).scaffoldBackgroundColor, width: 3)),
child: Center(
child: Text(
themeData.themeName,
style: GoogleFonts.poppins(
textStyle: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context).scaffoldBackgroundColor,
),
),
),
),
),
);
}
}
this is the dialog I have for the implementation:
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
elevation: 1,
backgroundColor: Theme.of(context).indicatorColor,
insetAnimationCurve: Curves.decelerate,
child: SizedBox(
height: 170,
width: 320,
child: Stack(
children: [
Padding(
padding: const EdgeInsets.only(
top: 25,
left: 35,
right: 35,
),
child: Stack(
children: [
Container(
width: 250,
height: 30,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(90),
color: Colors.black,
),
),
GestureDetector(
onTap: () {
selected = false;
print(selected);
},
child: AnimatedContainer(
duration: const Duration(
milliseconds: 200,
),
width: 138,
height: 30,
decoration: BoxDecoration(
color: Theme.of(context)
.indicatorColor,
borderRadius:
BorderRadius.circular(90),
border: Border.all(
color: Colors.black,
width: 1,
),
),
child: Center(
child: Text(
'Light Mode',
style: GoogleFonts.poppins(
textStyle: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 112,
),
child: GestureDetector(
onTap: () {
setState(() {
selected = true;
print(selected);
});
},
child: AnimatedContainer(
duration: const Duration(
milliseconds: 200,
),
width: 138,
height: 30,
decoration: BoxDecoration(
color: selected
? Colors.black
: Colors.transparent,
borderRadius:
BorderRadius.circular(90),
),
child: Center(
child: Text(
'Dark Mode',
style: GoogleFonts.poppins(
textStyle: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(
top: 85,
left: 35,
right: 35,
),
child: SizedBox(
height: 60,
width: 250,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: widgets),
),
),
],
),
),
);
getThemeManager:
/// Returns the [ThemeManger] that
ThemeManager getThemeManager(BuildContext context) =>
Provider.of<ThemeManager>(context, listen: false);
class ThemeModel {
final ThemeData? selectedTheme;
final ThemeData? darkTheme;
final ThemeMode? themeMode;
ThemeModel({
required this.selectedTheme,
required this.darkTheme,
required this.themeMode,
});
}

Error updating UI, setState() not working in flutter

I have two buttons on flutter screen (add to cart and remove from cart).
cartQuantity is a variable I have declared in my build() method to keep a track of users cart quantity.
When the user presses the add button, the UI for quantity x rate should change which doesn't seem to happen.
The Row widget contains 'REMOVE' button, user's cart quantity and 'ADD' button respectively.
class ItemBottomSheet extends StatefulWidget {
final RestaurantItems restaurantItem;
final Restaurant restaurant;
const ItemBottomSheet({
this.restaurantItem,
this.restaurant,
});
#override
_ItemBottomSheetState createState() => _ItemBottomSheetState();
}
class _ItemBottomSheetState extends State<ItemBottomSheet> {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final cartItems = Provider.of<Cart>(context).getCartItems;
final index = cartItems.indexWhere((cartItem) =>
cartItem.id == widget.restaurantItem.id &&
cartItem.restaurantId == widget.restaurant.id);
int restQuantity = widget.restaurantItem.quantity;
int cartQuantity = 0;
if (index != -1) {
cartQuantity = cartItems[index].quantity;
}
return Container(
decoration: new BoxDecoration(
color: darkThemeColour,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: new BoxDecoration(
color: Colors.transparent,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
height: size.height * 0.21,
width: double.infinity,
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
child: Image.network(
widget.restaurantItem.imageUrl,
fit: BoxFit.cover,
),
),
),
Row(
// crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
// SizedBox(
// height: 12,
// width: 12,
// child: SvgPicture.asset(
// 'lib/assets/icons/green-circle.svg',
// color: restaurantItem.isVeg ? Colors.green : Colors.red,
// ),
// ),
Padding(
padding: const EdgeInsets.only(top: 25, left: 18),
child: Text(
widget.restaurantItem.name,
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 21,
fontWeight: FontWeight.w600),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 17),
child: Text(
'₹${widget.restaurantItem.price}',
style: TextStyle(
color: Colors.green,
fontFamily: 'Raleway',
fontSize: 18,
fontWeight: FontWeight.w900),
),
),
Padding(
padding: const EdgeInsets.only(top: 27),
child: Text(
'Pickup Between',
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 14,
fontWeight: FontWeight.w300),
),
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
'${DateFormat.jm().format(widget.restaurant.pickupTime.start)} - ${DateFormat.jm().format(widget.restaurant.pickupTime.end)}',
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 17,
fontWeight: FontWeight.w400),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(top: 25, left: 18),
child: ClipOval(
child: Material(
color: index == -1 ||
cartItems[index].quantity == 0 ||
widget.restaurantItem.quantity <= 1
? Colors.grey
: Colors.green, // button color
child: InkWell(
splashColor: Colors.white30, // inkwell color
child: SizedBox(
width: 60,
height: 60,
child: Icon(
Icons.remove,
color: Colors.white,
size: 28,
)),
onTap: () {},
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(
cartQuantity > 0
? '$cartQuantity x ₹${widget.restaurantItem.price}'
: '₹${widget.restaurantItem.price}',
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 22,
fontWeight: FontWeight.w900),
),
),
Padding(
padding: const EdgeInsets.only(top: 25, right: 18),
child: ClipOval(
child: Material(
color: widget.restaurantItem.quantity <= 1
? Colors.grey
: Colors.green, // button color
child: InkWell(
splashColor: Colors.white30, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(
Icons.add,
color: Colors.white,
)),
onTap: () {
setState(() {
cartQuantity++;
print(cartQuantity.toString());
});
},
),
),
),
),
],
),
FillButton(
text: 'ADD TO CART',
function: () {
// setState(() {
// cartQuantity++;
// });
},
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(
widget.restaurantItem.isVeg ? 'VEG' : 'NON - VEG',
style: TextStyle(
fontFamily: 'Raleway',
fontSize: 17,
fontWeight: FontWeight.w800,
color:
widget.restaurantItem.isVeg ? Colors.green : Colors.red),
),
),
Container(
height: size.height * 0.3,
color: darkThemeColour,
)
],
),
);
}
}
Your issue is because in your build you are initialiazing your cartQuantity to 0 each time you do a rebuild of the widget. You should initialize it outside the build.
class _ItemBottomSheetState extends State<ItemBottomSheet> {
int cartQuantity = 0;
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final cartItems = Provider.of<Cart>(context).getCartItems;
final index = cartItems.indexWhere((cartItem) =>
cartItem.id == widget.restaurantItem.id &&
cartItem.restaurantId == widget.restaurant.id);
int restQuantity = widget.restaurantItem.quantity;
Now your value will not be always 0 because you initialize it in the construction of the widget. Each time you call setState you do a rebuild and you build gets called.

ListView isn't scrolling in Flutter

ListView is not working here, Firstly instead of padding I used Positioned() but there is a similar issue on github and there I got to know that scrollable widget shouldn't be placed inside Positioned() so i replaced it with Padding(), but got no success.
here is my code
import 'package:flutter/material.dart';
import 'package:cpblog/webview.dart';
import 'package:flutter/rendering.dart';
class DetailsPage extends StatefulWidget {
final heroTag;
final foodName;
final url;
final text;
DetailsPage({this.heroTag, this.foodName,this.url,this.text});
#override
_DetailsPageState createState() => _DetailsPageState();
}
class _DetailsPageState extends State<DetailsPage> {
var selectedCard = 'WEIGHT';
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF7A9BEE),
appBar: AppBar(
leading: IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
),
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text('Here You Go!!',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 18.0,
color: Colors.white)),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.more_horiz),
onPressed: () {},
color: Colors.white,
)
],
),
body: ListView(children: [
Stack(children: [
Container(
height: MediaQuery.of(context).size.height - 82.0,
width: MediaQuery.of(context).size.width,
color: Colors.transparent),
Padding(
padding: const EdgeInsets.only(top: 75.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(45.0),
topRight: Radius.circular(45.0),
),
color: Colors.white),
height: MediaQuery.of(context).size.height - 100.0,
width: MediaQuery.of(context).size.width),
),
Padding(
padding: EdgeInsets.only(top: 30.0,
left: (MediaQuery.of(context).size.width / 2) - 100.0,),
child: Hero(
tag: widget.heroTag,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(widget.heroTag),
fit: BoxFit.cover)),
height: 200.0,
width: 200.0)),
),
Padding(
padding: const EdgeInsets.only(top:250.0,right:25.0,left: 25.0),
child: ListView(
shrinkWrap: true,
children: <Widget>[
Text(widget.foodName,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 22.0,
fontWeight: FontWeight.bold)),
SizedBox(height: 20.0),
Text(widget.text,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 20.0,
)),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
width: 125.0,
height: 40.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(17.0),
color: Color(0xFF7A9BEE)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => WebView(widget.url, widget.foodName)));
},
child:Text('View More',
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat',
fontSize: 15.0)),
)
],
),
)
],
),
SizedBox(height: 20.0),
Container(
height: 150.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
_buildInfoCard('WEIGHT', '300', 'G'),
SizedBox(width: 10.0),
_buildInfoCard('CALORIES', '267', 'CAL'),
SizedBox(width: 10.0),
_buildInfoCard('VITAMINS', 'A, B6', 'VIT'),
SizedBox(width: 10.0),
_buildInfoCard('AVAIL', 'NO', 'AV')
],
)
),
SizedBox(height: 20.0),
Padding(
padding: EdgeInsets.only(bottom:5.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0), bottomLeft: Radius.circular(25.0), bottomRight: Radius.circular(25.0)),
color: Colors.black
),
height: 50.0,
child:
InkWell(
onTap: () {
Navigator.pop(context);
},
child: Center(
child: Text(
'Back',
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat'
)
),
),
)
),
)
],
),
)
])
]));
}
Widget _buildInfoCard(String cardTitle, String info, String unit) {
return InkWell(
onTap: () {
selectCard(cardTitle);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.easeIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: cardTitle == selectedCard ? Color(0xFF7A9BEE) : Colors.white,
border: Border.all(
color: cardTitle == selectedCard ?
Colors.transparent :
Colors.grey.withOpacity(0.3),
style: BorderStyle.solid,
width: 0.75
),
),
height: 100.0,
width: 100.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 15.0),
child: Text(cardTitle,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12.0,
color:
cardTitle == selectedCard ? Colors.white : Colors.grey.withOpacity(0.7),
)),
),
Padding(
padding: const EdgeInsets.only(left: 15.0, bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(info,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 14.0,
color: cardTitle == selectedCard
? Colors.white
: Colors.black,
fontWeight: FontWeight.bold)),
Text(unit,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12.0,
color: cardTitle == selectedCard
? Colors.white
: Colors.black,
))
],
),
)
]
)
)
);
}
selectCard(cardTitle) {
setState(() {
selectedCard = cardTitle;
});
}
}
I tried physics, listView.builder(),but everytime I get the same result.
Thank you in advance!!!!
Surround you ListView with Expanded widget.
You can't have a scrollable widget inside another scrollable widget without setting a proper height for the inner one. Or use ConstrainedBox