Related
I am making an app with flutter and in my application I made an hidden drawer by putting 2 pages in a Stack widget and when I click on the menu icon, the homepage gets an offset and the drawer screen becomes visible. On the drawerscreen I have 2 selfmade buttons which are supposede to lead you to another page.
My drawer in my homepage is setup with an AnimatedContainer>Listview>Column>Container as in the code below.
import 'package:flutter/material.dart';
import 'package:paws_up/components/buttons/animated_button.dart';
import 'package:paws_up/components/buttons/category_button.dart';
import 'package:paws_up/pages/product_overview_page.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
double xOffset = 0;
double yOffset = 0;
double scaleFactor = 1;
bool isDrawerOpen = false;
#override
Widget build(BuildContext context) {
return AnimatedContainer(
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.circular(40)),
duration: const Duration(milliseconds: 250),
transform: Matrix4.translationValues(xOffset, yOffset, 0)
..scale(scaleFactor),
child: ListView(
children: [
Column(
children: [
Container(
margin: const EdgeInsets.symmetric(
horizontal: 20,
),
height: 70,
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
isDrawerOpen
? IconButton(
onPressed: () {
setState(() {
xOffset = 0;
yOffset = 0;
scaleFactor = 1;
isDrawerOpen = false;
});
},
icon: const Icon(
Icons.chevron_left_rounded,
color: Color.fromARGB(255, 0, 0, 0),
),
)
: IconButton(
onPressed: () {
setState(() {
xOffset = 230;
yOffset = 150;
scaleFactor = 0.6;
isDrawerOpen = true;
});
},
icon: const Icon(
Icons.menu,
color: Color.fromARGB(255, 0, 0, 0),
),
),
const Text(
'PawsUp',
style: TextStyle(
color: Color(0xff363636),
fontFamily: 'Ubuntu',
fontWeight: FontWeight.bold,
fontSize: 24),
),
Row(
children: [
IconButton(
icon: const Icon(Icons.notifications_outlined,
color: Color(0xff363636)),
onPressed: () {
// do something
},
),
IconButton(
icon: const Icon(Icons.person_outline_rounded,
color: Color(0xff363636)),
onPressed: () {
// do something
},
),
],
),
],
),
),
Container(
margin: const EdgeInsets.symmetric(
vertical: 30,
horizontal: 20,
),
decoration: BoxDecoration(
color: const Color.fromARGB(255, 247, 247, 247),
borderRadius: BorderRadius.circular(8)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
IconButton(
icon: const Icon(FontAwesomeIcons.filter,
color: Color(0xff5891AC)),
onPressed: () {},
),
const Text(
'Search..',
style: TextStyle(
color: Color(0xffCAC9C9),
fontFamily: 'Poppins',
fontWeight: FontWeight.bold,
fontSize: 16),
),
],
),
Container(
decoration: BoxDecoration(
color: const Color(0xff5891AC),
borderRadius: BorderRadius.circular(8),
),
child: IconButton(
onPressed: () {},
icon: const Icon(
FontAwesomeIcons.magnifyingGlass,
color: Colors.white,
),
),
),
],
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 20),
height: 140,
decoration: BoxDecoration(
color: const Color(0xffD5E5F4),
borderRadius: BorderRadius.circular(15.0),
),
child: Stack(
children: [
Positioned(
top: 50,
left: 135,
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(0),
topRight: Radius.circular(0),
bottomLeft: Radius.circular(0),
bottomRight: Radius.circular(15)),
child: Image.asset(
'images/Banner_photo.jpg',
height: 90.0,
width: 190.0,
fit: BoxFit.cover,
),
),
),
Positioned(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.fromLTRB(15, 8, 0, 8),
child: Text(
'Join our animal loving community',
style: TextStyle(
color: Colors.white,
fontFamily: 'Poppins',
fontWeight: FontWeight.bold,
fontSize: 20),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 0, 0),
child: AnimatedButton(
height: 40,
width: 100,
text: 'Join Now',
textColor: const Color(0xffD5E5F4),
buttonColor: Colors.white,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ProductOverviewPage()),
);
},
),
),
],
),
),
],
),
),
Container(
margin: const EdgeInsets.symmetric(
vertical: 30,
horizontal: 20,
),
child: Column(
children: [
Row(
children: [
const Text(
'Pet Categories',
style: TextStyle(
color: Color(0xff363636),
fontFamily: 'Poppins',
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
const Spacer(),
TextButton(
onPressed: () {},
child: const Text(
'More Categroies',
style: TextStyle(
color: Color(0xff5891AC), fontFamily: 'Ubuntu'),
),
),
],
),
SizedBox(
height: 50,
child: ListView(
scrollDirection: Axis.horizontal,
children: const [
CategoryButton(
text: 'Cat',
buttonColor: Colors.white,
selectedButtonColor: Color(0xff5891AC),
contentColor: Color(0xff363636),
selectedContentColor: Colors.white,
isSelected: false,
icon: FontAwesomeIcons.cat,
),
CategoryButton(
text: 'Dog',
buttonColor: Colors.white,
selectedButtonColor: Color(0xff5891AC),
contentColor: Color(0xff363636),
selectedContentColor: Colors.white,
isSelected: false,
icon: FontAwesomeIcons.dog,
),
CategoryButton(
text: 'Fish',
buttonColor: Colors.white,
selectedButtonColor: Color(0xff5891AC),
contentColor: Color(0xff363636),
selectedContentColor: Colors.white,
isSelected: false,
icon: FontAwesomeIcons.fish,
),
CategoryButton(
text: 'Bird',
buttonColor: Colors.white,
selectedButtonColor: Color(0xff5891AC),
contentColor: Color(0xff363636),
selectedContentColor: Colors.white,
isSelected: false,
icon: FontAwesomeIcons.dove,
),
],
),
)
],
),
),
Container(
margin: const EdgeInsets.symmetric(
vertical: 30,
horizontal: 20,
),
child: Column(
children: [
Row(
children: [
const Text(
'Adopt Us',
style: TextStyle(
color: Color(0xff363636),
fontFamily: 'Poppins',
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
const Spacer(),
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ProductOverviewPage()),
);
},
child: const Text(
'See All',
style: TextStyle(
color: Color(0xff5891AC), fontFamily: 'Ubuntu'),
),
),
],
),
SizedBox(
height: 50,
child: ListView(
scrollDirection: Axis.horizontal,
children: const [],
),
)
],
),
),
],
),
],
),
);
}
}
The drawerScreen code is as follows:
import 'package:flutter/material.dart';
import 'package:paws_up/components/buttons/drawer_button.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:paws_up/pages/home_page.dart';
import 'package:paws_up/pages/product_overview_page.dart';
class DrawerScreen extends StatefulWidget {
const DrawerScreen({super.key});
#override
State<DrawerScreen> createState() => _DrawerScreenState();
}
class _DrawerScreenState extends State<DrawerScreen> {
#override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
color: Color(0xffD5E5F4),
),
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: const EdgeInsets.symmetric(
vertical: 20,
horizontal: 20,
),
child: Row(
children: [
const CircleAvatar(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'Firstname Lastname',
style: TextStyle(
color: Colors.white,
fontFamily: 'Ubuntu',
fontWeight: FontWeight.bold,
fontSize: 20),
),
Text(
'Location',
style: TextStyle(
color: Colors.white,
fontFamily: 'Poppins',
fontSize: 16),
)
],
),
)
],
),
),
Container(
child: Column(
children: [
DrawerButton(
text: 'Home',
icon: Icons.home,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
},
),
DrawerButton(
text: 'Adopt',
icon: FontAwesomeIcons.paw,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ProductOverviewPage()),
);
},
),
// DrawerButton(
// text: 'Donate',
// icon: FontAwesomeIcons.circleDollarToSlot,
// ),
// DrawerButton(
// text: 'Favorites',
// icon: FontAwesomeIcons.solidHeart,
// ),
// DrawerButton(
// text: 'Messages',
// icon: FontAwesomeIcons.solidEnvelope,
// ),
// DrawerButton(
// text: 'Profile',
// icon: FontAwesomeIcons.solidUser,
// ),
],
),
),
Container(
padding: const EdgeInsets.fromLTRB(0, 20, 0, 70),
child: Row(
children: [
// DrawerButton(
// text: 'Settings',
// icon: FontAwesomeIcons.gear,
// ),
// DrawerButton(
// text: 'Log in',
// icon: FontAwesomeIcons.arrowRightToBracket,
// ),
],
),
)
],
),
),
);
}
}
I think the problem lies in the DrawerButton. It is supposed to lead you to different pages but it doesn't. This is my DrawerButton code:
import 'package:flutter/material.dart';
class DrawerButton extends StatefulWidget {
final String text;
final IconData icon;
DrawerButton({
super.key,
required this.text,
required this.icon,
required Null Function() onTap,
});
#override
_DrawerButtonState createState() => _DrawerButtonState();
}
class _DrawerButtonState extends State<DrawerButton>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late double _scale;
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
lowerBound: 0.0,
upperBound: 0.1,
)..addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
_scale = 1 - _controller.value;
return GestureDetector(
onTapDown: _onTapDown,
onTapUp: _onTapUp,
child: Stack(
children: [
Transform.scale(
scale: _scale,
child: _DrawerButtonUi,
),
],
),
);
}
Widget get _DrawerButtonUi => Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
child: Row(
children: [
Icon(
widget.icon,
color: Colors.white,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(
widget.text,
style: const TextStyle(
color: Colors.white,
fontFamily: 'Poppins',
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
],
),
);
void _onTapDown(TapDownDetails details) {
_controller.forward();
}
void _onTapUp(TapUpDetails details) {
_controller.reverse();
}
}
I thought maybe it had something to do with the stack widget I have in the gesturedetector of my DrawerButton. I have tried navigator.of(context).push instead of navigator.push, but that does not seem to make a difference.
But I am not quite sure how I can build that widget differently, keep the animation and have the navigator push work.
Does anybody have a solution?
You need to create a widget variable in order to access on state class.
class DrawerButton extends StatefulWidget {
final String text;
final IconData icon;
final VoidCallback onTap; //this will be used
const DrawerButton({
super.key,
required this.onTap,
And will be called on
void _onTapDown(TapDownDetails details) {
_controller.forward();
widget.onTap();
}
Two Files:
account_page.dart
& cart_page.dart
I used Navigator.push to embed AccountPage() [from account_page.dart] within CartPage() (inside cart_page.dart). When I check the simulation, the background image widget within the Stack() changes position.
How can I make the NavigationPage identical to the original? Is this a bug?
I've tried many things including wrapping the Container() that holds the image in a Positioned(), SizedBox(), 'alignment: Alignment(x,y)', adding a column that shifts the image down. Most of these end with the picture completely disappearing, I erased parameters to make the image free as possible and then tried again to no avail.
Initially, I used 'alignment: Alignment(0.0, -7.0)' to position the image. However, when the page is called using Navigator, the image alignment changes from a negative to a positive causing the position to move the opposite direction.
The other solutions I've thought of require some photoshop, but I don't want to mess with the image unless I really have to.
I believe it has something to do with the image being in a stack and causing some overflow.
Any suggestions would be helpful.
Code:
account_page.dart
import 'package:email_validator/email_validator.dart';
import 'package:flutter/material.dart';
class AccountPage extends StatefulWidget {
const AccountPage({Key? key}) : super(key: key);
#override
_AccountPageState createState() => _AccountPageState();
}
class _AccountPageState extends State<AccountPage> {
bool _obscureText = true;
bool _passswordVisible = false;
void _toggleObscureText() {
setState(() {
_obscureText = !_obscureText;
_passswordVisible = !_passswordVisible;
});
}
String? get _showHideString {
if (!_passswordVisible) {
return "Show";
} else {
return "Hide";
}
}
#override
Widget build(BuildContext context) {
// create a global key that can provide validation
final _formKey = GlobalKey<FormState>();
return Form(
key: _formKey,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0,
),
body: Stack(
children: [
Container(
//*****************AREA OF PROBLEM**************************
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
color: Colors.white,
image: DecorationImage(
image: AssetImage("images/background.jpeg"),
fit: BoxFit.fitWidth,
//---------sets the position of image------------
alignment: Alignment(0.0, -7.0),
),
),
),
SingleChildScrollView(
child: Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.all(30.0),
child: Text(
"Sign in",
style: TextStyle(
fontFamily: "RaleWay",
fontSize: 30,
fontWeight: FontWeight.bold),
),
),
const Padding(
padding: EdgeInsets.only(left: 20, right: 20, bottom: 30),
child: Text(
"Become a member to enjoy exclusive savings on your favorite items.",
style: TextStyle(
fontSize: 16,
),
textAlign: TextAlign.center,
),
),
Stack(
children: <Widget>[
SingleChildScrollView(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 10),
child: Column(
children: [
TextFormField(
validator: (value) {
if (EmailValidator.validate(value!)) {
return null;
} else {
return "Please enter a valid Username";
}
},
autocorrect: false,
autofocus: false,
style: const TextStyle(fontSize: 18),
decoration: InputDecoration(
hintText: 'UserName',
border: InputBorder.none,
filled: true,
fillColor: Colors.grey[200],
contentPadding: const EdgeInsets.all(10.0),
),
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 25,
),
child: Stack(children: <Widget>[
TextFormField(
autocorrect: false,
autofocus: false,
obscureText: _obscureText,
style: const TextStyle(fontSize: 18),
decoration: InputDecoration(
hintText: "Password",
filled: true,
fillColor: Colors.grey[200],
contentPadding:
const EdgeInsets.all(10.0),
),
),
Container(
alignment: Alignment.bottomRight,
child: TextButton(
onPressed: () {
_toggleObscureText();
},
child: Text(_showHideString!),
style: ButtonStyle(
overlayColor:
MaterialStateProperty.all(
Colors.transparent)
// MaterialStateProperty
// .resolveWith<Color?>(
// (Set<MaterialState> states) {
// if (states.contains(
// MaterialState.pressed)) {
// return Theme.of(context)
// .colorScheme
// .primary
// .withOpacity(0);
// }
// }),
),
))
]),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
child: const Text(
"Forgot Password?",
style: TextStyle(
decoration: TextDecoration.underline,
),
),
onPressed: () {},
style: ButtonStyle(
overlayColor:
MaterialStateProperty.all<Color>(
Colors.transparent,
)),
),
],
),
RawMaterialButton(
onPressed: () {
// ignore: todo
// TODO: Checks if username and password is in the system, this will bring to real account page
// if not, replies, please enter a valid username and password
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Submitted!"),
),
);
}
},
constraints:
const BoxConstraints(minWidth: 300),
splashColor: Colors.black12,
fillColor: Colors.black,
padding:
const EdgeInsets.symmetric(vertical: 12),
child: const Text(
"Login",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
],
)
],
),
),
],
),
),
);
}
}
cart_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_mobile_sim_test_1/account_page.dart';
class CartPage extends StatefulWidget {
const CartPage({Key? key}) : super(key: key);
#override
_CartPageState createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text(
"Your Cart",
style: TextStyle(fontSize: 24, color: Colors.black),
),
elevation: 0,
backgroundColor: Colors.white,
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width,
height: 100,
alignment: Alignment.center,
padding: const EdgeInsets.all(10.0),
child: const Text(
"Your Shopping Bag is Empty",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
RawMaterialButton(
child: const Text("Sign In",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold)),
//*****************NAVIGATOR PUSH**************************
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const AccountPage()),
);
},
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width,
minHeight: 20),
padding: const EdgeInsets.all(12.0),
fillColor: Colors.black,
),
Stack(
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: const Divider(
color: Colors.grey,
thickness: 2,
),
),
),
Container(
color: Colors.transparent,
width: (MediaQuery.of(context).size.width),
alignment: Alignment.topCenter,
padding: const EdgeInsets.all(8.0),
child: Container(
color: Colors.white,
width: 40,
child: const Text(
"or",
style: TextStyle(
fontSize: 18,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
),
),
],
),
RawMaterialButton(
onPressed: () {},
child: const Text("Create Account",
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold)),
fillColor: Colors.white,
shape: const ContinuousRectangleBorder(
side: BorderSide(color: Colors.black, width: 2),
),
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width,
minHeight: 20.0),
padding: const EdgeInsets.all(12.0)),
Container(
color: Colors.blue,
width: MediaQuery.of(context).size.width,
height: 200,
alignment: Alignment.center,
padding: const EdgeInsets.all(20.0),
// child: ,
),
const Text(
"hello",
style: TextStyle(fontSize: 50),
textAlign: TextAlign.center,
),
Container(
color: Colors.blue,
width: MediaQuery.of(context).size.width,
height: 200,
alignment: Alignment.center,
padding: const EdgeInsets.all(20.0),
// child: ,
),
],
),
),
));
}
}
Correctly positioned background image(the black infinity)
Incorrectly positioned background image within a NavigatorPage(the black infinity)
I want to navigate to the previous page using the arrow icon I have added in this code. to where I want to add that code and tell me how to code that part. want to navigate from detail_screen.dart to home_page.dart using the arrow icon I have added. can someone please provide a proper answer for this?
detail_screen.dart
import 'package:flutter/material.dart';
class DetailsScreen extends StatelessWidget {
const DetailsScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
//shadowColor: Colors.transparent,
leading: Icon(
Icons.arrow_back_rounded,
color: Colors.black,
),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: const [
CircleAvatar(
radius: 40,
backgroundColor: Colors.white,
child:
Icon(Icons.favorite_border_outlined, color: Colors.black),
),
CircleAvatar(
radius: 40,
backgroundColor: Colors.white,
child: Icon(Icons.shopping_bag_outlined, color: Colors.black),
)
],
),
),
],
),
body: Column(
children: <Widget>[
Stack(
alignment: Alignment.bottomRight,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 0),
child: Container(
height: MediaQuery.of(context).size.height * 0.9,
width: MediaQuery.of(context).size.width * 0.9,
padding: const EdgeInsets.only(left: 20),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/image23.png"),
fit: BoxFit.contain,
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Colors.grey.shade100,
),
alignment: const Alignment(1, 1),
height: 310,
width: 375,
child: Column(
children: [
SizedBox(
height: 30,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
"Crop Top",
style: TextStyle(
fontSize: 24,
color: Color(0xff262626),
fontWeight: FontWeight.w700),
textAlign: TextAlign.left,
),
),
SizedBox(
height: 30,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: 25,
height: 25,
child: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.blueAccent,
child: null),
),
),
SizedBox(
width: 25,
height: 25,
child: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.amber,
child: null),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: SizedBox(
width: 25,
height: 25,
child: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.lightGreen,
child: null),
),
),
]),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 270, 10),
child: Text(
"Sizes",
style: TextStyle(
fontSize: 16,
color: Color(0xff262626),
fontWeight: FontWeight.w700),
textAlign: TextAlign.left,
),
),
// SizedBox(
// height: 30,
// ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(
style: TextButton.styleFrom(
side: BorderSide(
color: Colors.black,
),
),
onPressed: () {
print('XS');
},
child: Text('XS'),
),
TextButton(
style: TextButton.styleFrom(
side: BorderSide(
color: Colors.black,
),
),
onPressed: () {
print('X');
},
child: Text('S'),
),
TextButton(
style: TextButton.styleFrom(
side: BorderSide(
color: Colors.black,
),
),
onPressed: () {
print('M');
},
child: Text('M'),
),
TextButton(
style: TextButton.styleFrom(
side: BorderSide(
color: Colors.black,
),
),
onPressed: () {
print('L');
},
child: Text('L'),
),
TextButton(
style: TextButton.styleFrom(
side: BorderSide(
color: Colors.black,
),
),
onPressed: () {
print('XL');
},
child: Text('XL'),
),
],
),
SizedBox(
height: 30,
),
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"30% off",
style: TextStyle(
fontSize: 25,
color: Colors.purple,
fontWeight: FontWeight.w700),
),
),
],
),
SizedBox(
height: 30,
),
Row(
children: const [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Rs.2950",
style: TextStyle(
fontSize: 18,
color: Color(0xff8399A9),
fontWeight: FontWeight.w700,
decoration: TextDecoration.lineThrough),
),
),
Text(
"Rs.2750",
style: TextStyle(
fontSize: 24,
color: Color(0xff0DA75F),
fontWeight: FontWeight.w700,
),
),
],
),
],
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(230, 110, 0, 0),
child: ElevatedButton(
onPressed: () {},
child: const Text(
"Add to Cart ",
),
style: ElevatedButton.styleFrom(
primary: Colors.pinkAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
bottomRight: Radius.circular(20),
),
),
padding: const EdgeInsets.all(28),
),
),
),
],
),
],
),
);
}
}
home_page.dart
import 'package:flutter/material.dart';
import 'package:fashion_app/details_screen.dart';
import 'package:flutter/services.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//final double _borderRadious = 24;
#override
#override
void initState() {
// TODO: implement initState
super.initState();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.pinkAccent,
),
body: ListView(
padding: const EdgeInsets.only(top: 40, left: 20, right: 20),
children: [
HelloText(),
Name(),
SizedBox(
height: 10,
),
buildSearchInput(),
SizedBox(
height: 10,
),
Stack(children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 45, 10, 0),
child: TextButton(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Colors.red.shade50,
),
height: 137,
width: 327,
child: Column(
children: const [
Padding(
padding: const EdgeInsets.fromLTRB(20, 40, 100, 40),
child: Text(
"Summer Collections",
style: TextStyle(
fontSize: 24,
color: Color(0xff262626),
fontWeight: FontWeight.w700),
textAlign: TextAlign.justify,
),
),
],
)),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailsScreen()));
},
),
),
const Padding(
padding: EdgeInsets.fromLTRB(200, 0, 10, 0),
child: Image(
image: AssetImage("assets/images/dressone.png"),
),
),
]),
Stack(children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 45, 10, 0),
child: TextButton(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Colors.red.shade50,
),
height: 137,
width: 327,
child: Column(
children: const [
Padding(
padding: const EdgeInsets.fromLTRB(20, 40, 100, 40),
child: Text(
"Winter Collections",
style: TextStyle(
fontSize: 24,
color: Color(0xff262626),
fontWeight: FontWeight.w700),
textAlign: TextAlign.justify,
),
),
],
)),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailsScreen()));
},
),
),
const Padding(
padding: EdgeInsets.fromLTRB(200, 0, 10, 0),
child: Image(
image: AssetImage("assets/images/dresstwo.png"),
),
),
]),
Stack(children: [
Padding(
padding: const EdgeInsets.fromLTRB(5, 20, 10, 0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Colors.blue.shade50,
),
height: 137,
width: 327,
child: Row(
children: const [
Padding(
padding: EdgeInsets.fromLTRB(150, 40, 0, 40),
child: Text(
"Get",
style: TextStyle(
fontSize: 24,
color: Colors.black,
fontWeight: FontWeight.w700),
),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Text(
"30%",
style: TextStyle(
fontSize: 24,
color: Colors.purple,
fontWeight: FontWeight.w700),
),
),
Text(
"Off",
style: TextStyle(
fontSize: 24,
color: Colors.black,
fontWeight: FontWeight.w700),
),
],
)),
),
const Padding(
padding: EdgeInsets.fromLTRB(15, 0, 10, 0),
child: Image(
image: AssetImage("assets/images/dressthree.png"),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(230, 110, 0, 40),
child: ElevatedButton(
onPressed: () {},
child: const Text(
"Know More",
),
style: ElevatedButton.styleFrom(
primary: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
bottomRight: Radius.circular(20))),
padding: const EdgeInsets.all(15)),
),
),
]),
],
),
);
}
Widget HelloText() => Container(
child: Row(children: [
Text(
'Hello,',
style: TextStyle(
fontSize: 28,
color: Colors.black,
fontWeight: FontWeight.w500,
),
),
]),
);
Widget Name() => Container(
child: Row(children: [
Text(
'Nirasha',
style: TextStyle(
fontSize: 28,
color: Colors.amber,
fontWeight: FontWeight.w500,
),
),
]),
);
Widget buildSearchInput() => Container(
decoration: BoxDecoration(
color: Colors.grey[300], borderRadius: BorderRadius.circular(20)),
child: Padding(
padding: const EdgeInsets.only(left: 20.0, right: 20),
child: Row(
children: [
Icon(
Icons.search,
size: 30,
color: Colors.grey,
),
Flexible(
child: TextField(
decoration: InputDecoration(border: InputBorder.none),
),
),
],
),
),
);
}
use following Structure in detail_screen.dart scaffold:
body : SafeArea(
child: Column(
children: <Widget>[
Container(child: IconButton(
icon: Icon(
Icons.chevron_left_sharp, //backIcon
color: Colors.indigo,
size: 30,
),
onPressed: () {
Navigator.pop(context);
},
),
-------------------- //other Elements Of body
]
),
)
Please use this : Navigator.of(context).pop();
In your detail_screen.dart, use this code in Appbar leading.
IconButton(
icon: new Icon(
Icons.arrow_back_rounded,
color: Colors.black,
),
onPressed: () => Navigator.pop(context),
),
Used this code now it is working.
leading: IconButton(
icon: new Icon(
Icons.arrow_back_rounded,
color: Colors.black,
),
onPressed: () {Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage()));
},
),
In your DetailScreen, your leading widget should be IconButton and handle onpressed event of that IconButton to pop the activity from stack.
Here it is:
leading: IconButton(
icon: new Icon(
Icons.arrow_back_rounded,
color: Colors.black,
),
onPressed: () => Navigator.pop(context),
),
I am trying to achieve a UI in which there are 2 buttons in the center and then afterwards there are 2 rows at the bottom of the screen fixed respective to screen sizes I will stay at its place, but I'm unable to do it in my case I'm using Column and all the other containers and rows are in it.
Desired Result on emulator is fine
What I am getting in real device
Here is the code.
class IntroPage extends StatelessWidget {
const IntroPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF29F76),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Image.asset(
"assets/intropage.png",
fit: BoxFit.fill,
),
Padding(
padding: const EdgeInsets.only(
top: 550,
),
child: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignUpPage()));
},
child: Container(
width: 180,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.white,
),
borderRadius:
const BorderRadius.all(Radius.circular(40))),
child: const Center(
child: Text(
"Sign Up",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black),
),
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(
top: 650,
),
child: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignInPage()));
},
child: Container(
width: 180,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.white,
),
borderRadius:
const BorderRadius.all(Radius.circular(40))),
child: const Center(
child: Text(
"Sign In",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFFFE6B01)),
),
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(
top: 750,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 2,
width: 150,
color: Colors.white,
),
const Text(
" Please Read ",
style: TextStyle(color: Colors.white),
),
Container(
height: 2,
width: 150,
color: Colors.white,
),
],
),
),
Padding(
padding: const EdgeInsets.only(
top: 760,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 20, top: 6),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
TermsandConditions()));
},
child: const Text(
"Terms & Conditions",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 20, top: 6),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PrivacyPolicy()));
},
child: const Text(
"Privacy Policy",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
),
],
),
),
],
)
],
),
),
);
}
}
Use this method its will do the job. Background image will appear and you can align your widgets using the Alignment property
class IntroPage extends StatelessWidget {
const IntroPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage(
'assets/intropage.png',
),
)),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.only(top: 250.0),
child: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignUpPage()));
},
child: Container(
width: 180,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.white,
),
borderRadius:
const BorderRadius.all(Radius.circular(40))),
child: const Center(
child: Text(
"Sign Up",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black),
),
),
),
),
),
),
),
Align(
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.only(top: 500.0),
child: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignInPage()));
},
child: Container(
width: 180,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.white,
),
borderRadius:
const BorderRadius.all(Radius.circular(40))),
child: const Center(
child: Text(
"Sign In",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFFFE6B01)),
),
),
),
),
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 2,
width: 150,
color: Colors.white,
),
const Text(
" Please Read ",
style: TextStyle(color: Colors.white),
),
Container(
height: 2,
width: 150,
color: Colors.white,
),
],
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 20, top: 6),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TermsandConditions()));
},
child: const Text(
"Terms & Conditions",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 20, top: 6),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PrivacyPolicy()));
},
child: const Text(
"Privacy Policy",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
),
],
),
),
],
)),
);
}
}
Try to wrap your widgets inside
Positioned(
Align(
alignment: Alignment.bottomCenter,
child: _your_widget_here()
It's not recommanded to use fix value for the layout.
Stack here it's not necessary.
A simple Spacer Widget can the work. But there are multiple way to do it.
import 'package:flutter/material.dart';
class IntroPage extends StatelessWidget {
const IntroPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF29F76),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Image.asset(
"assets/intropage.png",
fit: BoxFit.fitWidth,
),
const Spacer(),
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignUpPage()));
},
child: Container(
width: 180,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.white,
),
borderRadius:
const BorderRadius.all(Radius.circular(40))),
child: const Center(
child: Text(
"Sign Up",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black),
),
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SignInPage()));
},
child: Container(
width: 180,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.white,
),
borderRadius:
const BorderRadius.all(Radius.circular(40))),
child: const Center(
child: Text(
"Sign In",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFFFE6B01)),
),
),
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 2,
width: 150,
color: Colors.white,
),
const Text(
" Please Read ",
style: TextStyle(color: Colors.white),
),
Container(
height: 2,
width: 150,
color: Colors.white,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 20, top: 6),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
TermsandConditions()));
},
child: const Text(
"Terms & Conditions",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 20, top: 6),
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PrivacyPolicy()));
},
child: const Text(
"Privacy Policy",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
),
],
),
],
),
),
);
}
}
If you can use standard buttons, use them. I used ElevatedButton with custom styles, so please check it.
In general it is a bad idea to add accumulated top padding to each element. Screens sizes are different and your layout will be failed on another screen size.
Please see my example of how to do this better.
Also I added other small improvements, maybe you will be interested in.
class IntroPage extends StatelessWidget {
const IntroPage({Key? key}) : super(key: key);
Widget _createButton({
required VoidCallback onPressed,
required Widget child,
required Color textColor,
}) {
return ElevatedButton(
onPressed: onPressed,
child: child,
style: ElevatedButton.styleFrom(
elevation: 0.0,
primary: Colors.white,
onPrimary: textColor,
textStyle: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
padding: EdgeInsets.all(8.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
fixedSize: Size(180.0, 60.0),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF29F76),
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: Stack(
children: <Widget>[
Align(
alignment: Alignment.topCenter,
child: SizedBox(
height: 400.0, //your image height
child: Image.network(
"https://images.ctfassets.net/hrltx12pl8hq/61DiwECVps74bWazF88Cy9/2cc9411d050b8ca50530cf97b3e51c96/Image_Cover.jpg?fit=fill&w=480&h=270",
fit: BoxFit.cover,
),
),
),
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_createButton(
child: Text("Sign Up"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
//your page
builder: (context) => Container(),
),
);
},
textColor: Colors.black,
),
SizedBox(height: 32.0),
_createButton(
child: Text("Sign In"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
//your page
builder: (context) => Container(),
),
);
},
textColor: Color(0xFFFE6B01),
),
SizedBox(height: 32.0),
],
),
),
],
),
),
_BottomSection(),
],
),
),
);
}
}
class _BottomSection extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Expanded(
child: Divider(
height: 2,
thickness: 2,
color: Colors.white,
),
),
SizedBox(width: 10),
Text(
"Please Read",
style: TextStyle(color: Colors.white),
),
SizedBox(width: 10),
Expanded(
child: Divider(
height: 2,
thickness: 2,
color: Colors.white,
),
),
],
),
Padding(
padding: const EdgeInsets.only(
top: 6.0,
right: 20.0,
left: 20.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => Container()));
},
child: const Text(
"Terms & Conditions",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
GestureDetector(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => Container()));
},
child: const Text(
"Privacy Policy",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline),
),
),
],
),
),
],
);
}
}
I have more than 10 buttons that I need to display in my flutter. Here's the sample code for my 2 repetitive buttons:
Padding(
padding: const EdgeInsets.all(8.0),
child: Material(
clipBehavior: Clip.antiAlias,
shape: const StadiumBorder(),
child: Ink(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black,
Colors.grey,
Colors.white,
],
),
),
width: double.infinity,
height: 60,
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PrivacyRoute()),
);
},
child: ListTile(
leading: Icon(
Icons.menu_book,
color: Colors.white,
),
title: Text('Bahasa Melayu',
style: TextStyle(
color: Colors.white,
fontSize: 20,
)),
),
),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Material(
clipBehavior: Clip.antiAlias,
shape: const StadiumBorder(),
child: Ink(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black,
Colors.grey,
Colors.white,
],
),
),
width: double.infinity,
height: 60,
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PrivacyRoute()),
);
},
child: ListTile(
leading: Icon(
Icons.menu_book,
color: Colors.white,
),
title: Text('English',
style: TextStyle(
color: Colors.white,
fontSize: 20,
)),
),
),
),
),
),
The non-repetitive is only the colours of linear-gradient, onTap, icon and the text. Any idea how? I tried using the void function but was unable to achieve a usable function. Hope to get some insights from you guys.
Make it a StatelessWidget class
class MyButton extends StatelessWidget {
final VoidCallback onTap;
final List<Color> colors;
final Widget icon;
final String text;
const MyButton({
Key? key,
required this.onTap,
required this.colors,
required this.icon,
required this.text,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Material(
clipBehavior: Clip.antiAlias,
shape: const StadiumBorder(),
child: Ink(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: colors,
),
),
width: double.infinity,
height: 60,
child: InkWell(
onTap: onTap,
child: ListTile(
leading: icon,
title: Text(text,
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
),
),
),
);
}
}
Now it's up to you if you want those parameters as required or you will have some defaults value in case they are null etc. (for example if you don't pass colors maybe have a cosnt list of colors to use in that case)