I need help with the Flexible widget.
Widget build(BuildContext context) {
return Padding(
padding : EdgeInsets.all(20),
child: RawMaterialButton(
onPressed: onPressed,
elevation: 4.0,
fillColor: Theme.of(context).primaryColor,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: PreferredSize(
preferredSize: Size.fromHeight(30.0),
child: AppBar(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
automaticallyImplyLeading: false,
centerTitle: true,
title: Text(title),
)
),
body: Column(
children: [
Flexible(
child: Image.network(
link,
fit:BoxFit.fill
),
),
Padding(
padding: EdgeInsets.fromLTRB(0,10,0,10),
child: Divider(),
),
Text(
type,
overflow: TextOverflow.fade,
style: TextStyle(
wordSpacing: 1.0,
fontStyle: FontStyle.italic
),
),
Text(
"Prezzo: "+price.toString()+"€",
overflow: TextOverflow.ellipsis,
),
],
),
),
),
);
}
the method works because the image follows the size of the window, but if I make it too small the image disappears and gives me this error.
I have made several attempts but have not found a solution to the problem.
EDIT:
basically my panel looks like this but if I try to make it too small it gives me this error.
Related
I am quite new to Flutter and Dart development.
I am trying to display a list of all of the items in a JSON List that match a particular criteria, with the criteria being a type of alcohol in this case. I have created an IF statement at the top of what the ListBuilder returns, but it only returns the first item in the list when it matches the criteria. For example, I have three objects where the category is "Rum", but it still only returns the first one. Any help or advice would be greatly appreciated! Thank you!
class CocktailCategoryList extends StatefulWidget {
#override
_CocktailListState createState() => _CocktailListState();
}
class _CocktailListState extends State<CocktailCategoryList> {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: Container(
height: 55,
width: 55,
child: FittedBox(
child: Container(
height: 60,
width: 60,
child: FloatingActionButton(
backgroundColor: Color.fromRGBO(86, 99, 255, 100),
onPressed: () {
},
child: Icon(
Icons.shuffle,
color: Colors.white,
size: 35,
),
),
),
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.miniCenterDocked,
bottomNavigationBar: BottomAppBar(
elevation: 20,
shape: CircularNotchedRectangle(),
child: Container(
height: 55,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
iconSize: 30,
padding: EdgeInsets.only(left: 28),
icon: Icon(
Icons.home,
),
onPressed: () {
Navigator.pop(context);
},
),
IconButton(
iconSize: 30,
padding: EdgeInsets.only(right: 28),
icon: Icon(
Icons.list,
color: Colors.purple[700],
),
onPressed: () {},
),
IconButton(
iconSize: 30,
padding: EdgeInsets.only(left: 28),
icon: Icon(Icons.person),
onPressed: () {},
),
IconButton(
iconSize: 30,
padding: EdgeInsets.only(right: 28),
icon: Icon(Icons.search),
onPressed: () {},
),
],
),
),
),
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: IconThemeData(
color: Colors.black,
),
centerTitle: true,
title: Text(
"Cocktails",
style: TextStyle(color: Colors.black),
),
),
body: Center(
child: FutureBuilder(
builder: (context, snapshot) {
var cocktailData = json.decode(snapshot.data.toString());
return ListView.builder(
itemCount: cocktailData == null ? 0 : cocktailData.length,
itemBuilder: (BuildContext context, int index) {
if (cocktailData[index]['category'] == "Rum"){
Column(
children: [
SafeArea(
minimum: EdgeInsets.fromLTRB(15, 0, 15, 0),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CocktailPage(
cocktailData[index]['name'],
cocktailData[index]['subtitle'],
cocktailData[index]['category'],
cocktailData[index]['instructions'],
cocktailData[index]['image'],
cocktailData[index]['ingredients'],
))),
child: Container(
width: MediaQuery.of(context).size.width,
child: Wrap(children: [
Image(
image: NetworkImage(cocktailData[index]['image']),
),
]),
),
),
),
GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CocktailPage(
cocktailData[index]['name'],
cocktailData[index]['subtitle'],
cocktailData[index]['category'],
cocktailData[index]['instructions'],
cocktailData[index]['image'],
cocktailData[index]['ingredients'],
))),
child: ListTile(
visualDensity:
VisualDensity(horizontal: 0, vertical: -1),
title: Row(
children: [
Text(
cocktailData[index]['name'],
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(
width: 5,
),
CategoryTag(
cocktailData[index]['category']) //Button Here
],
),
subtitle: Text(cocktailData[index]['subtitle']),
),
),
SizedBox(height: 10)
],
);
}else {
SizedBox();
}
}
);
},
future:
DefaultAssetBundle.of(context).loadString('assets/testJson.json'),
),
),
);
}
}
One thing I noticed is that you are not returning the Column widget in your ListView.builder() inside of the if statement. The anonymous builder function that you provide to the ListView.builder() should always return a widget.
I have created a dialogue box in my flutter app and i want it to be reusable. So each time i call it i pass in two arguments, the text to be displayed to the user and the function to be executed if they confirm the action. here is the code
The dialogue widget
child: Column(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(
top: 30.0, left: 20.0, right: 20.0),
child: Text(
//The text argument is passed here
widget.text,
style: TextStyle(color: Colors.grey[600], fontSize: 16.0),
),
)),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: ButtonTheme(
height: 35.0,
minWidth: 110.0,
child: RaisedButton(
color: Colors.black,
shape: buttonShapeDeco,
splashColor: Colors.black.withAlpha(40),
child: Text(
widget.button,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 13.0),
),
onPressed: ()async{
//I expect the passed function to be executed here after the user confirms the action
await widget.action;
}
},
)),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 10.0, top: 10.0, bottom: 10.0),
child: ButtonTheme(
height: 35.0,
minWidth: 110.0,
child: RaisedButton(
color: Colors.black,
shape: buttonShapeDeco,
splashColor: Colors.white.withAlpha(40),
child: Text(
'Cancel',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 13.0),
),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
))
),
],
))
],
)),
In my instance 'm trying to sign out a user only after they press the confirm button to logout.
Here is the code
onTap: ()async{
showDialog(
context: context,
builder: (_) => Dialogue(text: 'Are you sure you want to logout?',button: 'Logout',action: _auth.signOut(),pop:true),
);
},
The problem is the function is executed as soon as the dialogue box is opened, before the user can confirm the action.
How can i get around this?
change the action from _auth.signOut() to ()=>_auth.signOut()
onTap: ()async{
showDialog(
context: context,
builder: (_) => Dialogue(text: 'Are you sure you want to logout?',button: 'Logout',action: ()=>_auth.signOut(),pop:true),
);
}
In your Dialogue widget you need to change the type of action parameter to Future<dynamic> Function(). And then pass _auth.signOut function to it.
Dialogue Widget
class Dialogue extends StateFulWidget {
Future<dynamic> Function() action;
//other code
}
Pass the signOut function to it
onTap: ()async{
showDialog(
context: context,
builder: (_) => Dialogue(text: 'Are you sure you want to logout?', button: 'Logout', action: _auth.signOut, pop:true),
);
}
On some devices, the maps display fine. However, some times, when I scroll to the very bottom and scroll up slowly, the map overlap App Bar instead of start disappearing from my view (as the other widgets).
I've tested it in more than 4 different devices and simulators, and nothing happens. However it does happen on my friend's smartphone, I don't know why. Have anyone ever saw this bug? [screenshot of the bug][1]
children: <Widget>[
Stack(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.width,
child: GoogleMap(
onMapCreated: (mapController) {
_mapController = mapController;
try {
_addMarker();
} catch (e) {
print(e.toString());
_scaffoldKey.currentState.showSnackBar(
buildSnackBar('Request location error'));
}
},
markers: _markers,
mapType: MapType.normal,
scrollGesturesEnabled: false,
initialCameraPosition: CameraPosition(target: LatLng(_lead.latitude, _lead.longitude)),
)),
Column(
children: <Widget>[
Table(
columnWidths: {0: FlexColumnWidth(1), 1: FlexColumnWidth(1)},
children: [
_buildTableRow('Installation Address:',
_lead.installationAddressLineOne,
color: COLOR_LIGHT_GREY.withAlpha(150))
],
),
addDivider(),
Text(
'Roof Location',
style:
TextStyle(fontWeight: FontWeight.w600, color: Colors.red),
),
],
),
],
),
Container(
child: ButtonTheme(
height: 32,
minWidth: double.infinity,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
buttonColor: Colors.indigo,
padding: EdgeInsets.only(left: 10, right: 10),
child: RaisedButton(
child: Text(
'Route to lead',
style: TextStyle(color: Colors.white),
),
onPressed: () {
final url =
'https://www.google.com/maps/dir/?api=1&destination=${_lead.latitude},${_lead.longitude}';
launch(url);
},
),
),
)
],
);
[1]: https://i.stack.imgur.com/lAmL9.png
I am trying to make a floating search bar on top of my map, the same way there is a search bar in the Google Maps app. Something like this -
I can't seem to make it to be floating. The search bar does not overlay on the map. It rather just renders in its own box.
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
theme: ThemeData.dark(),
home: MyAppState(),
));
}
class MyAppState extends StatelessWidget {
final LatLng _center = const LatLng(28.535517, 77.391029);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: FloatAppBar(),
body: Map(_center),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Report()),
);
},
child: Icon(Icons.add, semanticLabel: 'Action'),
backgroundColor: Colors.black87,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomNavBar(),
),
);
}
}
class FloatAppBar extends StatelessWidget with PreferredSizeWidget {
#override
Widget build(BuildContext context) {
return (FloatingSearchBar(
trailing: CircleAvatar(
child: Text("RD"),
),
drawer: Drawer(
child: Container(),
),
onChanged: (String value) {},
onTap: () {},
decoration: InputDecoration.collapsed(
hintText: "Search...",
),
children: [
],
));
}
#override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
}
I expect the search bar to float on top of the map but it renders in its own box.
I have achieved the same results in here:
Code:
Stack(
children: <Widget>[
// Replace this container with your Map widget
Container(
color: Colors.black,
),
Positioned(
top: 10,
right: 15,
left: 15,
child: Container(
color: Colors.white,
child: Row(
children: <Widget>[
IconButton(
splashColor: Colors.grey,
icon: Icon(Icons.menu),
onPressed: () {},
),
Expanded(
child: TextField(
cursorColor: Colors.black,
keyboardType: TextInputType.text,
textInputAction: TextInputAction.go,
decoration: InputDecoration(
border: InputBorder.none,
contentPadding:
EdgeInsets.symmetric(horizontal: 15),
hintText: "Search..."),
),
),
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: CircleAvatar(
backgroundColor: Colors.deepPurple,
child: Text('RD'),
),
),
],
),
),
),
],
),
UPDATE
I think this will be more suitable for you now => FloatingSearchBar by Rody Darvis :")
I have a SliverAppBar that I want to be hidden when the user scrolls down on the page. The problem is that I have a Google Map widget that is causing the app bar to move as well, when I only want it to move only when my touch is off the Google Map. Is there a way to prevent this?
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
backgroundColor: Colors.transparent,
elevation: 5.0,
pinned: false,
snap: false,
floating: false,
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
background: Image.asset(
'assets/events/city.jpeg',
fit: BoxFit.cover,
),
),
),
SliverFillRemaining(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
height: 200,
width: double.infinity,
child: GoogleMap(
initialCameraPosition:
CameraPosition(target: LatLng(50.0, 50.0)),
onMapCreated: (controller) {
setState(() {
_googleMapController = controller;
});
},
),
),
)
],
),
),
)
],
),
));
}
I found that adding a gestureRecognizer property to GoogleMap and passing in a Factory of type VerticalDragRecognizer allowed it to prevent the SliverAppBar from scrolling. It also works on any kind of scrolling you want for your app. See this for more info about it around the 50 minute mark.
SliverFillRemaining(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
height: 200,
width: double.infinity,
child: GoogleMap(
gestureRecognizers: Set()..add(Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer()
)),
scrollGesturesEngabled: true,
initialCameraPosition:
CameraPosition(target: LatLng(50.0, 50.0)),
onMapCreated: (controller) {
setState(() {
_googleMapController = controller;
});
},
),
),
)
],
),
),
)