So I got some cars with all the technical data (top speed, horsepower, etc.) saved in my backend and my app gets all this data. Like you can see in my first screenshot (SC1) the user chooses what kind of car he is looking for and when he presses on this yellow button a bottomsheet appears (SC2) (SC3) and he can select the different characteristics of the car.
What I'm trying to achieve is that the item which was chosen by the user is displayed when he closes the bottomsheet again. So basically it shall be displayed what was chosen, for example on (SC1) right behind the text "Brand", "Price", etc.
This is the code of the first Screenshot (SC1):
class SearchTab extends StatefulWidget {
const SearchTab({Key key}) : super(key: key);
#override
_SearchTabState createState() => _SearchTabState();
}
class _SearchTabState extends State<SearchTab> {
ScrollController _scrollController;
#override
void initState() {
_scrollController = ScrollController();
super.initState();
}
bool _more = false;
#override
Widget build(BuildContext context) {
final FilterProvider filterProvider = Provider.of<FilterProvider>(context);
return filterProvider.isLoading // --- DAS WAR DAVOR DA! ---
? Container(
constraints: const BoxConstraints.expand(),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xffFEFDFD),
Color(0xffBDBDB2),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Center(
child: CupertinoActivityIndicator(
// CircularProgressIndicator(
// color: Colors.grey,
// ),
),
),
)
: Container(
constraints: const BoxConstraints.expand(),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFEFDFD), Color(0xffBDBDB2)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0,
0), //Original: const EdgeInsets.fromLTRB(15, 20, 15, 0),
child: Scrollbar(
controller: _scrollController,
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
controller: _scrollController,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
children: <Widget>[
FilterButtonWidget(
title: 'Brand',
item: constants.brand,
type: 'brand',
),
FilterButtonWidget(
title: 'Price',
item: constants.price,
type: 'price',
),
FilterButtonWidget(
title: 'Engine Power [kW]',
item: constants.enginepower,
type: 'engine',
),
FilterButtonWidget(
title: 'Range',
item: constants.range,
type: 'range',
),
FilterButtonWidget(
title: 'Battery [kWh]',
item: constants.battery,
type: 'battery',
),
FilterButtonWidget(
title: 'Loading Power [kW]',
item: constants.chargingpower,
type: 'charging',
),
FilterButtonWidget(
title: 'Top speed',
item: constants.topspeed,
type: 'top',
),
GestureDetector(
onTap: () {
setState(() => _more = !_more);
_scrollController.animateTo(
_more
? _scrollController.offset +
MediaQuery.of(context).size.height * .3
: _scrollController
.position.minScrollExtent,
curve: _more ? Curves.easeIn : Curves.easeOut,
duration: const Duration(milliseconds: 500));
},
const SizedBox(height: 20),
],
),
),
),
),
),
);
}
}
And this is the code of my FilterButtonWidget:
class FilterButtonWidget extends StatelessWidget {
const FilterButtonWidget({
Key key,
this.title,
this.item,
this.type,
}) : super(key: key);
final String title;
final dynamic item;
final String type;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Stack(
children: <Widget>[
Container(
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
gradient: const LinearGradient(
colors: [Colors.white, Colors.white],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
boxShadow: const [
BoxShadow(
color: Colors.grey,
blurRadius: 0,
offset: Offset(0, 0),
),
],
),
),
Row(
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
),
Expanded(
flex: 1,
child: Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 0, 0),
child: Text(
title,
style: const TextStyle(
fontFamily: 'Avenir',
fontSize: 16.0,
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
child: TextButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(const Color(0xffF2F2F2)),
padding:
MaterialStateProperty.all(const EdgeInsets.all(0.0)),
shape: MaterialStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(7.0),
),
),
),
overlayColor: MaterialStateColor.resolveWith(
(states) => Colors.transparent),
foregroundColor: MaterialStateColor.resolveWith(
(states) => Color(0xff424242)),
),
//minWidth: 70,
child: Ink(
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [
Color(0xffFBD23E),
Color(0xffF6BE03),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
borderRadius: BorderRadius.circular(7.0)),
child: Container(
constraints:
const BoxConstraints(maxHeight: 40, maxWidth: 70),
alignment: Alignment.center,
child: const Icon(
Icons.arrow_forward_ios_rounded,
size: 22,
),
),
),
onPressed: () {
_bottomsheet(context);
},
),
),
],
),
],
),
);
}
void _bottomsheet(context) {
final FilterProvider filterProvider =
Provider.of<FilterProvider>(context, listen: false);
final _type = type;
showModalBottomSheet(
context: context,
isDismissible: true,
backgroundColor: Colors.transparent,
builder: (context) => Container(
height: MediaQuery.of(context).size.height * 0.60,
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFEFDFD), Color(0xffBDBDB2)],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(22.0),
topRight: Radius.circular(22.0),
),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 15, 20, 12),
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 0, 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: const TextStyle(
color: Color(0xffF6BE03),
fontFamily: 'Avenir',
fontWeight: FontWeight.w600,
fontSize: 24.0,
),
),
// IconButton(
// onPressed: () {
// Navigator.pop(context);
// },
// icon: const Icon(Icons.arrow_downward),
// iconSize: 30,
// ),
],
),
),
if (type == 'body' || type == 'drive' || type == 'brand')
CheckboxWidget(
item: item,
type: type,
state: filterProvider.filter,
)
else if (type == 'seats')
CupertinoMultiPicker(
state: filterProvider.filter['seats'],
)
else
CupertinoPickerWidget(
item: item,
type: type,
)
],
),
),
),
).whenComplete(() => filterProvider.apply = true);
}
}
Related
[enter image description here][1] [![enter image description here][1]][1] import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:ionicons/ionicons.dart';
void main() {
runApp(const MyApp((), key:,));
}
class MyApp extends StatelessWidget {
const MyApp(Type myApp, {required Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.blue),
home: const SinginPage(key:,),
);
}
}
class SinginPage extends StatefulWidget {
const SinginPage({required Key key}) : super(key: key);
#override
_SinginPageState createState() => _SinginPageState();
}
class _SinginPageState extends State<SinginPage> {
bool obscureText = false;
final TextEditingController _email = TextEditingController();
final TextEditingController _password = TextEditingController();
final emailGlobalKey = GlobalKey<FormState>();
final passwordGlobalKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
var currentWidth = MediaQuery.of(context).size.width;
var small = currentWidth > 1201;
var extraSmall = currentWidth > 1025;
var Validators;
return Scaffold(
backgroundColor: Colors.white,
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: extraSmall ? MediaQuery.of(context).size.height : 0.0,
width: small
? MediaQuery.of(context).size.width * 0.72
: extraSmall
? MediaQuery.of(context).size.width - 500
: 0.0,
color: Colors.indigo[200],
child: Image.network(
'https://cdn.pixabay.com/photo/2021/10/11/13/12/website-6700615_960_720.png',
fit: BoxFit.cover,
),
),
Stack(
alignment: Alignment.topRight,
children: [
Container(
height: MediaQuery.of(context).size.height,
width: small ? MediaQuery.of(context).size.width * 0.28 : 500,
alignment: Alignment.center,
color: Colors.white,
child: Container(
padding: const EdgeInsets.all(60.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 45.0),
Container(
alignment: Alignment.topLeft,
child: const Text(
'WELCOME BACK :)',
style: TextStyle(
color: Colors.black,
fontSize: 40.0,
fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 65.0),
Container(
alignment: Alignment.topLeft,
child: const Text('Email'),
),
Form(
key: emailGlobalKey,
child: TextFormField(
onChanged: (value) {
setState(() {
_email.text = value;
});
},
decoration: const InputDecoration(
prefixIcon: Padding(
padding:
EdgeInsets.only(right: 20.0, bottom: 1.0),
child: Icon(Icons.email_outlined,
color: Colors.black45, size: 24.0),
),
contentPadding: EdgeInsets.only(top: 15.0, left: 0),
hintStyle: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.grey),
hintText: 'Email',
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.indigo, width: 2.0),
),
),
validator: Validators.required('Email is required!'),
),
),
const SizedBox(height: 25.0),
Container(
alignment: Alignment.topLeft,
child: const Text('Password'),
),
Form(
key: passwordGlobalKey,
child: TextFormField(
obscureText: obscureText,
onChanged: (value) {
setState(() {
_password.text = value;
});
},
decoration: InputDecoration(
suffixIcon: obscureText
? InkWell(
onTap: () {
setState(() {
obscureText = false;
});
},
child: const Icon(Ionicons.eye,
color: Colors.black54, size: 25.0),
)
: InkWell(
onTap: () {
setState(() {
obscureText = true;
});
},
child: const Icon(Ionicons.eye_off,
color: Colors.black54, size: 25.0),
),
prefixIcon: const Padding(
padding:
EdgeInsets.only(right: 20.0, bottom: 1.0),
child: Icon(Icons.lock_outline,
color: Colors.black45, size: 25.0),
),
contentPadding:
const EdgeInsets.only(top: 15.0, left: 0),
hintStyle: const TextStyle(
fontWeight: FontWeight.normal,
color: Colors.grey),
hintText: 'Password',
focusedBorder: const UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.indigo, width: 2.0),
),
),
validator:
Validators.required('Password is required!'),
),
),
const SizedBox(height: 10.0),
Container(
alignment: Alignment.topRight,
child: TextButton(
style: TextButton.styleFrom(
padding: const EdgeInsets.all(0.0)),
onPressed: () {},
child: const Text('Forgot Password'),
)),
const SizedBox(
height: 50.0,
),
SizedBox(
height: 45.0,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: _password.text != ''
? _password.text != ''
? Colors.indigo
: Colors.indigo[300]
: Colors.indigo[300],
elevation: 0.0,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0)),
padding: const EdgeInsets.only(
left: 30.0,
top: 0.0,
right: 30.0,
bottom: 0.0)),
onPressed: () {
emailGlobalKey.currentState?.validate();
passwordGlobalKey.currentState?.validate();
},
child: const Text('LOGIN',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold)),
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 30.0),
child: const Text('OR'),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Material(
color: Colors.indigo,
borderRadius: BorderRadius.circular(50.0),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(
Ionicons.logo_facebook,
color: Colors.white,
size: 30.0,
),
),
),
),
),
InkWell(
onTap: () {},
child: Padding(
padding:
const EdgeInsets.only(left: 8.0, right: 8.0),
child: Material(
color: Colors.red,
borderRadius: BorderRadius.circular(50.0),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(
Ionicons.logo_google,
color: Colors.white,
size: 30.0,
),
)),
),
),
InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Material(
color: Colors.blue,
borderRadius: BorderRadius.circular(50.0),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(
Ionicons.logo_twitter,
color: Colors.white,
size: 30.0,
),
),
),
),
),
],
),
SizedBox(height: small ? 100.0 : 60.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("I don't have an account?"),
TextButton(
onPressed: () {},
child: const Text(
"Sign up",
style: TextStyle(color: Colors.blue),
),
)
],
),
],
),
),
),
Container(
padding: const EdgeInsets.only(top: 30.0, right: 50),
child: Icon(Ionicons.settings_outline,
color: Colors.black12.withOpacity(0.03), size: 80.0),
),
],
),
],
),
);
}
}
** how can I make my code organized well and put some text after the sign in page or sign up as u see I have some errors here idk how will I organize my code to make it perfect so please anyone can help fixing the errors and let me do a text or a table like a market adds and let the code neatly and nice so I can understand where I can write a text or do a new cons and type what I want
well see now i have got an running issue problem I didn't get what u want to say**
You have a problem with they key
Try this:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp((), key: UniqueKey(),));
}
class MyApp extends StatelessWidget {
const MyApp(Type myApp, {required Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.blue),
home: SinginPage(key: UniqueKey()),
);
}
}
class SinginPage extends StatefulWidget {
const SinginPage({required Key key}) : super(key: key);
#override
_SinginPageState createState() => _SinginPageState();
}
class _SinginPageState extends State<SinginPage> {
bool obscureText = false;
final TextEditingController _email = TextEditingController();
final TextEditingController _password = TextEditingController();
final emailGlobalKey = GlobalKey<FormState>();
final passwordGlobalKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
var currentWidth = MediaQuery.of(context).size.width;
var small = currentWidth > 1201;
var extraSmall = currentWidth > 1025;
var Validators;
return Scaffold(
backgroundColor: Colors.white,
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: extraSmall ? MediaQuery.of(context).size.height : 0.0,
width: small
? MediaQuery.of(context).size.width * 0.72
: extraSmall
? MediaQuery.of(context).size.width - 500
: 0.0,
color: Colors.indigo[200],
child: Image.network(
'https://cdn.pixabay.com/photo/2021/10/11/13/12/website-6700615_960_720.png',
fit: BoxFit.cover,
),
),
Stack(
alignment: Alignment.topRight,
children: [
Container(
height: MediaQuery.of(context).size.height,
width: small ? MediaQuery.of(context).size.width * 0.28 : 500,
alignment: Alignment.center,
color: Colors.white,
child: Container(
padding: const EdgeInsets.all(60.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 45.0),
Container(
alignment: Alignment.topLeft,
child: const Text(
'WELCOME BACK :)',
style: TextStyle(
color: Colors.black,
fontSize: 40.0,
fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 65.0),
Container(
alignment: Alignment.topLeft,
child: const Text('Email'),
),
Form(
key: emailGlobalKey,
child: TextFormField(
onChanged: (value) {
setState(() {
_email.text = value;
});
},
decoration: const InputDecoration(
prefixIcon: Padding(
padding:
EdgeInsets.only(right: 20.0, bottom: 1.0),
child: Icon(Icons.email_outlined,
color: Colors.black45, size: 24.0),
),
contentPadding: EdgeInsets.only(top: 15.0, left: 0),
hintStyle: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.grey),
hintText: 'Email',
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.indigo, width: 2.0),
),
),
validator: Validators.required('Email is required!'),
),
),
const SizedBox(height: 25.0),
Container(
alignment: Alignment.topLeft,
child: const Text('Password'),
),
Form(
key: passwordGlobalKey,
child: TextFormField(
obscureText: obscureText,
onChanged: (value) {
setState(() {
_password.text = value;
});
},
decoration: InputDecoration(
suffixIcon: obscureText
? InkWell(
onTap: () {
setState(() {
obscureText = false;
});
},
child: const Icon(Ionicons.eye,
color: Colors.black54, size: 25.0),
)
: InkWell(
onTap: () {
setState(() {
obscureText = true;
});
},
child: const Icon(Ionicons.eye_off,
color: Colors.black54, size: 25.0),
),
prefixIcon: const Padding(
padding:
EdgeInsets.only(right: 20.0, bottom: 1.0),
child: Icon(Icons.lock_outline,
color: Colors.black45, size: 25.0),
),
contentPadding:
const EdgeInsets.only(top: 15.0, left: 0),
hintStyle: const TextStyle(
fontWeight: FontWeight.normal,
color: Colors.grey),
hintText: 'Password',
focusedBorder: const UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.indigo, width: 2.0),
),
),
validator:
Validators.required('Password is required!'),
),
),
const SizedBox(height: 10.0),
Container(
alignment: Alignment.topRight,
child: TextButton(
style: TextButton.styleFrom(
padding: const EdgeInsets.all(0.0)),
onPressed: () {},
child: const Text('Forgot Password'),
)),
const SizedBox(
height: 50.0,
),
SizedBox(
height: 45.0,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: _password.text != ''
? _password.text != ''
? Colors.indigo
: Colors.indigo[300]
: Colors.indigo[300],
elevation: 0.0,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0)),
padding: const EdgeInsets.only(
left: 30.0,
top: 0.0,
right: 30.0,
bottom: 0.0)),
onPressed: () {
emailGlobalKey.currentState?.validate();
passwordGlobalKey.currentState?.validate();
},
child: const Text('LOGIN',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold)),
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 30.0, vertical: 30.0),
child: const Text('OR'),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Material(
color: Colors.indigo,
borderRadius: BorderRadius.circular(50.0),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(
Ionicons.logo_facebook,
color: Colors.white,
size: 30.0,
),
),
),
),
),
InkWell(
onTap: () {},
child: Padding(
padding:
const EdgeInsets.only(left: 8.0, right: 8.0),
child: Material(
color: Colors.red,
borderRadius: BorderRadius.circular(50.0),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(
Ionicons.logo_google,
color: Colors.white,
size: 30.0,
),
)),
),
),
InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Material(
color: Colors.blue,
borderRadius: BorderRadius.circular(50.0),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(
Ionicons.logo_twitter,
color: Colors.white,
size: 30.0,
),
),
),
),
),
],
),
SizedBox(height: small ? 100.0 : 60.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text("I don't have an account?"),
TextButton(
onPressed: () {},
child: const Text(
"Sign up",
style: TextStyle(color: Colors.blue),
),
)
],
),
],
),
),
),
Container(
padding: const EdgeInsets.only(top: 30.0, right: 50),
child: Icon(
Ionicons.settings_outline,
color: Colors.black12.withOpacity(0.03),
size: 80.0,
),
),
],
),
],
),
);
}
}
I want to have a custom sliver appBar with a search bar in it. I made a normal app bar that looks like this : But I want that when we scroll down, the app bar looks like that :
Actually, the code of the normal app bar is just a green AppBar of elevation: 0 and just below I add my Header(). Here's the code of my Header :
class Header extends StatefulWidget {
String title;
IconData icon;
Header({#required this.title, #required this.icon});
#override
_HeaderState createState() => _HeaderState();
}
class _HeaderState extends State<Header> {
TextEditingController _editingController;
#override
void initState() {
super.initState();
_editingController = TextEditingController();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return PreferredSize(
preferredSize: size,
child: Container(
margin: EdgeInsets.only(bottom: kDefaultPadding * 2.5),
height: size.height*0.2,
child: Stack(
children: [
Container(
height: size.height*0.2-27,
width: size.width,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(36),
bottomRight: Radius.circular(36),
)
),
child: Align(
alignment: Alignment.topCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(widget.title, style: Theme.of(context).textTheme.headline4.copyWith(color: Colors.white, fontWeight: FontWeight.bold)),
SizedBox(width: 20,),
Icon(widget.icon, size: 40, color: Colors.white,)
],
)),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: kDefaultPadding),
padding: EdgeInsets.symmetric(horizontal: kDefaultPadding),
height: 54,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [BoxShadow(
offset: Offset(0, 10),
blurRadius: 50,
color: Theme.of(context).primaryColor.withOpacity(0.23),
)]
),
child: Row(
children: [
Expanded(
child: TextField(
controller: _editingController,
textAlignVertical: TextAlignVertical.center,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(color: Theme.of(context).primaryColor.withOpacity(0.5)),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
),
),
_editingController.text.trim().isEmpty ? IconButton(
icon: Icon(Icons.search, color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: null) :
IconButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
icon: Icon(Icons.clear, color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: () => setState(() {
_editingController.clear();
})),
],
),
),
)
],
),
),
);
}
#override
void dispose() {
_editingController.dispose();
super.dispose();
}
}
Any help to build this is welcome.
I've made a simple example to show the main logic.
Create your own SliverPersistentHeaderDelegate and calculate shrinkFactor.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white70,
body: CustomScrollView(
slivers: [
SliverPersistentHeader(
pinned: true,
floating: false,
delegate: SearchHeader(
icon: Icons.terrain,
title: 'Trees',
search: _Search(),
),
),
SliverFillRemaining(
hasScrollBody: true,
child: ListView(
physics: NeverScrollableScrollPhysics(),
children: [
Text('some text'),
Placeholder(
color: Colors.red,
fallbackHeight: 200,
),
Container(
color: Colors.blueGrey,
height: 500,
)
],
),
)
],
),
);
}
}
class _Search extends StatefulWidget {
_Search({Key key}) : super(key: key);
#override
__SearchState createState() => __SearchState();
}
class __SearchState extends State<_Search> {
TextEditingController _editingController;
#override
void initState() {
super.initState();
_editingController = TextEditingController();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 20, right: 5),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: TextField(
controller: _editingController,
// textAlignVertical: TextAlignVertical.center,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: 'Search',
hintStyle: TextStyle(
color: Theme.of(context).primaryColor.withOpacity(0.5)),
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
),
),
),
_editingController.text.trim().isEmpty
? IconButton(
icon: Icon(Icons.search,
color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: null)
: IconButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
icon: Icon(Icons.clear,
color: Theme.of(context).primaryColor.withOpacity(0.5)),
onPressed: () => setState(
() {
_editingController.clear();
},
),
),
],
),
);
}
}
class SearchHeader extends SliverPersistentHeaderDelegate {
final double minTopBarHeight = 100;
final double maxTopBarHeight = 200;
final String title;
final IconData icon;
final Widget search;
SearchHeader({
#required this.title,
this.icon,
this.search,
});
#override
Widget build(
BuildContext context,
double shrinkOffset,
bool overlapsContent,
) {
var shrinkFactor = min(1, shrinkOffset / (maxExtent - minExtent));
var topBar = Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
alignment: Alignment.center,
height:
max(maxTopBarHeight * (1 - shrinkFactor * 1.45), minTopBarHeight),
width: 100,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(title,
style: Theme.of(context).textTheme.headline4.copyWith(
color: Colors.white, fontWeight: FontWeight.bold)),
SizedBox(
width: 20,
),
Icon(
icon,
size: 40,
color: Colors.white,
)
],
),
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(36),
bottomRight: Radius.circular(36),
)),
),
);
return Container(
height: max(maxExtent - shrinkOffset, minExtent),
child: Stack(
fit: StackFit.loose,
children: [
if (shrinkFactor <= 0.5) topBar,
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: EdgeInsets.only(
bottom: 10,
),
child: Container(
alignment: Alignment.center,
child: search,
width: 200,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.white,
boxShadow: [
BoxShadow(
offset: Offset(0, 10),
blurRadius: 10,
color: Colors.green.withOpacity(0.23),
)
]),
),
),
),
if (shrinkFactor > 0.5) topBar,
],
),
);
}
#override
double get maxExtent => 230;
#override
double get minExtent => 100;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => true;
}
I am trying to display a container with some designs if it gets some data from firestore but if there is no data from firestore I want it to show a text saying no data from firestore, but it is not working and I'm getting errors.
...............................................................................................................................
below is the code, is this correct? getStoriesFunction:
Widget _getStories() {
Live users;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: getStory(users),
);
}
Widget getStory(Live user) {
return Container(
margin: EdgeInsets.all(12),
child: Column(
children: <Widget>[
user.isLive == true
? Container(
height: 55,
width: 55,
child: GestureDetector(
onTap: () {
// Join function
onJoin(
channelName: user.displayName,
channelId: user.channelId,
displayName: displayName,
hostImage: user.image,
userImage: image);
},
child: Stack(
alignment: Alignment(0, 0),
children: <Widget>[
Container(
height: 60,
width: 60,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: [
Colors.red,
Colors.redAccent,
Colors.red
],
begin: Alignment.topLeft,
end: Alignment.bottomRight)),
),
),
Container(
height: 55.5,
width: 55.5,
child: CircleAvatar(
backgroundColor: Colors.black,
),
),
CachedNetworkImage(
imageUrl: user.image,
imageBuilder: (context, imageProvider) => Container(
width: 52.0,
height: 52.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: imageProvider, fit: BoxFit.cover),
),
),
),
Container(
height: 70,
width: 70,
alignment: Alignment.bottomCenter,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
height: 17,
width: 25,
decoration: new BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(
Radius.circular(
4.0) // <--- border radius here
),
gradient: LinearGradient(
colors: [Colors.black, Colors.black],
begin: Alignment.centerLeft,
end: Alignment.centerRight),
),
),
Container(
decoration: new BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(
Radius.circular(
2.0) // <--- border radius here
),
gradient: LinearGradient(
colors: [
Colors.red,
Colors.redAccent
],
begin: Alignment.centerLeft,
end: Alignment.centerRight),
),
child: Padding(
padding: const EdgeInsets.all(3.0),
child: Text(
'LIVE',
style: TextStyle(
fontSize: 7,
color: Colors.white,
fontWeight: FontWeight.bold),
),
)),
],
))
],
),
))
: Text('No data in firestore',
style: TextStyle(
color: Colors.black,
fontSize: 12,
))
],
));
}
I have corrected you code and tested in the DartPad and work well for me. You can test to just copy and pase. It something wrong with user data from the firebase looks like bool isLive always true.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
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> {
// Fake user data
bool userExist = false;
void _toggleUserState() {
setState(() => userExist = !userExist);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_getStories(userExist),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _toggleUserState,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _getStories(bool user) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: getStory(user),
);
}
Widget getStory(bool user) {
return Container(
margin: EdgeInsets.all(12),
child: user == true
? Column(
children: <Widget>[
Container(
height: 55,
width: 55,
child: GestureDetector(
onTap: () {
// Join function
print('Join Function');
},
child: Stack(
alignment: Alignment(0, 0),
children: <Widget>[
Container(
height: 60,
width: 60,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: [
Colors.red,
Colors.redAccent,
Colors.red
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
),
),
Container(
height: 55.5,
width: 55.5,
child: CircleAvatar(
backgroundColor: Colors.black,
),
),
// Cached Image container here.
Container(
height: 55.5,
width: 55.5,
child: Text('Cached Image'),
),
Container(
height: 70,
width: 70,
alignment: Alignment.bottomCenter,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Container(
height: 17,
width: 25,
decoration: new BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(
Radius.circular(4.0),
),
gradient: LinearGradient(
colors: [Colors.black, Colors.black],
begin: Alignment.centerLeft,
end: Alignment.centerRight),
),
),
Container(
decoration: new BoxDecoration(
shape: BoxShape.rectangle,
borderRadius:
BorderRadius.all(Radius.circular(2.0)),
gradient: LinearGradient(
colors: [Colors.red, Colors.redAccent],
begin: Alignment.centerLeft,
end: Alignment.centerRight),
),
child: Padding(
padding: const EdgeInsets.all(3.0),
child: Text(
'LIVE',
style: TextStyle(
fontSize: 7,
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
),
],
),
)
],
),
),
)
],
)
: Text(
'No data in firestore',
style: TextStyle(
color: Colors.black,
fontSize: 12,
),
),
);
}
}
I have an app screen that uses Checkboxes and a Drop down Menu. However, I have realised I'd coded it inside a StatelessWidget so I am unable to change the state when an option is selected. How do I get this working so that when a Checkbox is selected then it will display as being "checked" rather than empty?
I have tried pasting in my code into a Stateful Widget, however keep running into errors, as I am not totally sure on which parts should go where.
import 'package:carve_brace_app/model/activity.dart';
import 'package:flutter/material.dart';
class DetailPage extends StatelessWidget {
final Activity activity;
DetailPage({Key key, this.activity}) : super(key: key);
#override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: 2.0,
valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Container(
width: 90.0,
child: new Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
activity.activityName,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
"Last Run: 3-2-19\n"+
"Last Avg Strain: 34%\n"+
"Last Run Time: 00:45:23",
style: TextStyle(color: Colors.white),
))),
// Expanded(flex: 1, child: newRow)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.45,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Color.fromRGBO(33, 147, 176, 100),
Color.fromRGBO(109, 213, 237, 100)
],
),
),
child: Center(
child: topContentText,
),
),
Positioned(
left: 235.0,
top: 180.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: new CircleAvatar(
radius: 80.0,
backgroundImage: NetworkImage(activity.icon),
backgroundColor: Colors.white,
),
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
"Config:",
style: TextStyle(fontSize: 18.0),
);
final mappedCheckbox = CheckboxListTile(
title: Text("Mapped"),
value: false,
onChanged: (newValue) { },
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final rtCheckBox = CheckboxListTile(
title: Text("Real-time Tracking"),
value: false,
onChanged: (newValue) { },
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final descriptionText = Text(
"Description:",
style: TextStyle(fontSize: 12.0),
);
final description = TextFormField(
decoration: InputDecoration(
hintText: 'Enter an activity description',
),
);
final scheduledFor = Text(
"Scheduled for:",
style: TextStyle(fontSize: 12.0),
);
final dropdown = new DropdownButton<String>(
items: <String>['Now (Default)', 'B', 'C', 'D'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
hint: Text("Now (Default)"),
onChanged: (_) {},
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: 170,//MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Colors.lightBlue,
child:
Text("Start", style: TextStyle(color: Colors.white, fontSize: 20)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, mappedCheckbox, rtCheckBox, descriptionText, description, Text("\n"), scheduledFor, dropdown, readButton],
),
),
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
}
}
Hover on to the StatelessWidget class and use
Android Studio:
Mac: option + enter
Windows: alt + enter
Visual Studio Code:
Mac: cmd + .
Windows: ctrl + .
Output (Your solution):
Here is the working code.
class DetailPage extends StatefulWidget {
final Activity activity;
DetailPage({Key key, this.activity}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
bool _tracking = false, _mapped = false; // you need this
String _schedule;
#override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(backgroundColor: Color.fromRGBO(209, 224, 224, 0.2), value: 2.0, valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Container(
width: 90.0,
child: Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
widget.activity.activityName,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
"Last Run: 3-2-19\n" + "Last Avg Strain: 34%\n" + "Last Run Time: 00:45:23",
style: TextStyle(color: Colors.white),
))),
// Expanded(flex: 1, child: newRow)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.45,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Color.fromRGBO(33, 147, 176, 100), Color.fromRGBO(109, 213, 237, 100)],
),
),
child: Center(
child: topContentText,
),
),
Positioned(
left: 235.0,
top: 180.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: CircleAvatar(
radius: 80.0,
backgroundColor: Colors.white,
),
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
"Config:",
style: TextStyle(fontSize: 18.0),
);
final mappedCheckbox = CheckboxListTile(
title: Text("Mapped"),
value: _mapped,
onChanged: (newValue) => setState(() => _mapped = newValue),
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final rtCheckBox = CheckboxListTile(
title: Text("Real-time Tracking"),
value: _tracking,
onChanged: (newValue) => setState(() => _tracking = newValue),
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final descriptionText = Text(
"Description:",
style: TextStyle(fontSize: 12.0),
);
final description = TextFormField(
decoration: InputDecoration(
hintText: 'Enter an activity description',
),
);
final scheduledFor = Text(
"Scheduled for:",
style: TextStyle(fontSize: 12.0),
);
final dropdown = DropdownButton<String>(
value: _schedule,
items: <String>['Now (Default)', 'B', 'C', 'D'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text("Now (Default)"),
onChanged: (newValue) {
setState(() {
_schedule = newValue;
});
},
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: 170, //MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Colors.lightBlue,
child: Text("Start", style: TextStyle(color: Colors.white, fontSize: 20)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, mappedCheckbox, rtCheckBox, descriptionText, description, Text("\n"), scheduledFor, dropdown, readButton],
),
),
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
}
}
For VSCode (Visual Studio Code) use ctrl + '.' keys while the cursor on the stateless widget to convert it to stateful widget.
You could use intellij's or vscode shortcut by hitting alt + enter or selecting the bulb icon while your cursor is on the name of the stateless widget then select convert to stateful widget
For Android Studio in Mac:
1.Place the marker on the Stateless widget name
2.Hit Alt+Enter
3.Select Convert to Stateful widget
4.Configure your Stateful widget based on your requirements
Adding a solution for Android Studio since I didn't find one here.
Place the marker on the Stateless widget name:
Hit Alt+Enter
Select Convert to Stateful widget
Configure your Stateful widget based on your requirements
Map item;
List data;
Future getdata() async{
http.Response response= await http.get(Uri.encodeFull("https://talaikis.com/api/quotes/"));
item=json.decode(response.body);
setState(() {
data=item["quotes"];
});
debugPrint(data.toString());
}
I want to display this request in stateful widget which is like this
#override
Widget build(BuildContext context) {
return new Scaffold(
drawer: drawerLeft(),
appBar: AppBar(
title: Text(
"IN TIME",
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w700),
),
backgroundColor: clr,
elevation: 0.0,
leading: MaterialButton(
child: Icon(
Icons.view_headline,
color: Colors.black,
),
onPressed: () {
scaffoldKey.currentState.openDrawer();
},
)),
key: scaffoldKey,
body: AnimatedContainer(
padding: EdgeInsets.only(top: 50.0),
duration: Duration(milliseconds: 1000),
curve: Curves.ease,
color: clr,
child: PageView.builder(
itemCount: 7, //7days
onPageChanged: (int page) {
this.setState(() {
Random rnd;
rnd = new Random();
int r = 0 + rnd.nextInt(_colors.length - 0);
clr = _colors[r];
});
},
controller: pageViewController,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Stack(
children: <Widget>[
Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
),
height:
MediaQuery.of(scaffoldKey.currentContext).size.height -
150.0,
width:
MediaQuery.of(scaffoldKey.currentContext).size.width -
20.0,
child: Stack(
children: <Widget>[
Positioned(
width: MediaQuery.of(scaffoldKey.currentContext)
.size
.width -
100.0,
left: index != currentPage
? getMappedValue(20.0, 100.0, 160.0, 20.0, pos)
: getMappedValue(20.0, 100.0, 20.0, -120.0, pos),
top: 20.0,
child: Opacity(
opacity: index != currentPage
? getMappedValue(20.0, 100.0, 0.0, 01.0, pos)
: getMappedValue(20.0, 100.0, 01.0, 00.0, pos),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
_days[index],
maxLines: 1,
softWrap: true,
style: TextStyle(
color: Colors.deepOrange,
fontSize: 22.0,
fontWeight: FontWeight.w600),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text(
'Quote for the day',
softWrap: true,
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.w300),
),
),
],
),
),
),
],
),
),
],
),
);
},
),
),
);
}
}
*Please help me out *
If I understand, you want to display the quotes under some padding that are being retrieved to your List which I'll assume to be an inferenced List<String>. If so, you could just use a ListView within your widget tree to display every fetched item in that list, like so:
(...)
data != null
? Padding(
padding: const EdgeInsets.only(top: 15.0),
child: ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(data[index]),
);
},
),
)
: Container(),
(...)