Consider I have two views, Orders view and Order Details view.
I would like to display an overlay (small section at the bottom) on Orders view, and when user selects an Order, we display Details view, but I want to continue to show the overlay, I want push route change so the back button etc work.
Is this doable
Use showModalBottomSheet
more examples: modal_bottom_sheet_demo persistent_bottom_sheet_demo
exam:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Modal bottom sheet'),
),
body: Center(
child: RaisedButton(
child: const Text('SHOW BOTTOM SHEET'),
onPressed: () {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return Container(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Text(
'This is the modal bottom sheet. Tap anywhere to dismiss.',
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).accentColor, fontSize: 24.0),
),
),
);
},
);
},
),
),
);
}
Related
Is it possible we can add onPressed action on the logo and start another activity?
I am creating a simple flutter app where I have used AppBar and in leading icon I have used a custom logo. I am not sure how to perform onPressed method so that it starts another activity. Anyone please help me here. Below is my app bar code.
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
"assets/images/logo.png",
),
),
title: Text('Safe Outs Business'),
),
body: Center(
child: Text('Admin HomePage'),
),
);
}
}
Click here to see a sample Image of the layout I am trying to build in flutter
You can embed your logo inside a GestureDetector:
return Scaffold(
appBar: AppBar(
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () => print('TAPPED!'),
child: Image.asset(
"assets/images/logo.png",
),
),
),
title: Text('Safe Outs Business'),
),
body: Center(
child: Text('Admin HomePage'),
),
);
I am using Cards in Flutter and want Progress Indicator at the left bottom position for 2 seconds while Tap on the card so that another page load successfully.
Does anyone know how to add?
Container(
height: 130,
child: Card(
child: Row(
children: <Widget>[
Expanded(
child: ListTile(
title: Text(
'My card Location',
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.w700),
),
leading: Icon(Icons.setting),
// color: Colors.blueAccent, size: mediumIconSize),
trailing: Icon(Icons.keyboard_arrow_right),
selected: true,
onTap: () async {
// I try this one but not working
// Flushbar(
//
// showProgressIndicator: true,
// duration: Duration(seconds: 2),
// );
getDetails().then((myCardlocations) {
Navigator
.of(context)
.pushNamed('/myCardlocations',
arguments: ObjectLocations(locations, 'myCardlocations'));
}
);
}
),
),
],
),
),
),
You can do something like this using Stack and CircularProgressIndicator..
class _MyWidgetState extends State<MyWidget> {
bool isLoading = false;
#override
Widget build(BuildContext context) {
return Container(
height: 130,
child: Stack(
children: [
Container(
height: 130,
child: Card(
child: Row(
children: <Widget>[
Expanded(
child: ListTile(
title: Text(
'My card Location',
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.w700),
),
leading: Icon(Icons.settings),
// color: Colors.blueAccent, size: mediumIconSize),
trailing: Icon(Icons.keyboard_arrow_right),
selected: true,
onTap: () async {
setState(() {
isLoading = true;
});
getDetails().then((myCardLocations) {
setState(() {
isLoading = false;
});
// navigation code here
});
},
),
),
],
),
),
),
Align(
alignment: Alignment.bottomLeft,
child: isLoading
? Padding(
padding: EdgeInsets.fromLTRB(15,0,0,15),
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(),
),
)
: SizedBox(),
),
],
),
);
}
}
Edit:
Looks like I misunderstood the question a bit. Specifically, the place where to show the progress indicator. Anyways, if you get the idea, you can put the indicator at a different place as per your requirement.
There are certain things, which I would like to mention before I give the actual answer.
Read about Flutter.delayed constructor, very useful thing to make some thing wait for a while and do the operation by providing Duration. Whatever you want to do after that duration, it will implement in the callback function
Future.delayed(Duration(seconds: your_time, (){
//it will perform this operation after that much of seconds
}));
You can always show/hide a Widget using bool value, and make changes accordingly
Use a column and Add the LinearProgressIndicator at the end of the Widget. Show/hide it based up on the data
Also, use MediaQuery to give out the height. It is more efficient way of giving the dimensions according to all phone size. Like match-parent in Android Studio. Do the math accordingly, I have shown in the code also
Column(
children: [
Row(),
bool val ? LinearProgressIndicator() : Container() // Container() is nothing but an empty widget which shows nothing
]
)
Some heads up: I have not used getData, since it is not defined properly but you can call it the in function which I will show you in the code, that is pageTransit(). Follow the comments and you are good to go
class _MyHomePageState extends State<MyHomePage> {
// this takes care of the show/hide of your progress indicator
bool _showProgress = false;
// this takes care of the operation
void pageTransit(){
// first show when the ListTile is clicked
setState(() => _showProgress = true);
Future.delayed(Duration(seconds: 2), (){
// hide it after 2 seconds
setState(() => _showProgress = false);
// do the page trnasition here
//getDetails().then((myCardlocations) {
//Navigator.of(context).pushNamed('/myCardlocations',
//arguments: ObjectLocations(locations, 'myCardlocations'));
//}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: MediaQuery.of(context).size.height * 0.1,
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// use your items here, based upon the bool value show hide your
// progress indicator
Row(
children: <Widget>[
Expanded(
child: ListTile(
title: Text(
'My card Location',
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.w700),
),
leading: Icon(Icons.settings),
// color: Colors.blueAccent, size: mediumIconSize),
trailing: Icon(Icons.keyboard_arrow_right),
selected: true,
onTap: () => pageTransit()
)
)
]
),
// show/hide in the card
_showProgress ? LinearProgressIndicator() : Container()
]
)
)
)
);
}
}
Result
Look at the ProgressIndicator, it remains there for 2 seconds, and then goes away
1. You need to define a GlobalKey for the Scaffold so that you can use a SnackBar (you can define the GloablKey in your page's State).
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
2. You need to set the key for the Scaffold.
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
...
3. You need to wrap the Card with a GestureDetector and set the onTap function to call showLoading which shows a SnackBar on the bottom of the screen. Call your getDetails function in the showLoading. Full code (except the define key step):
void _showLoading() {
_scaffoldKey.currentState.showSnackBar(new SnackBar(
duration: new Duration(seconds: 2),
content: new Row(
children: <Widget>[
new CircularProgressIndicator(),
new Text("Loading...")
],
),
));
// call to your getDetails and its steps should be here
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text("My app"),
),
body: Center(
child: GestureDetector(
child: Card(
child: Row(children: <Widget>[
Expanded(
child: ListTile(
title: Text(
'My card Location',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700),
),
leading: Icon(Icons.settings),
// color: Colors.blueAccent, size: mediumIconSize),
trailing: Icon(Icons.keyboard_arrow_right),
selected: true,
)),
])),
onTap: () => _showLoading(),
)),
);
}
}
Note: you can also style the SnackBar.
Result:
I want to show a video in a alertDialog widget but i don't know how to show it in a alertDialog widget. here is my code.
class ResultScreen extends StatelessWidget {
static const routeResult = '/result-screen';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('The Result'),
backgroundColor: Colors.brown,
elevation: 0.0),
drawer: SideManu(),
body: ListView(children: <Widget>[
Container(
child: Stack(children: <Widget>[
Background(),
MoodText(),
ShowLevel(),
ActivityText(),
ActivityClip()
]))
]));
}
}
this is my code for button to open a video
class ActivityClip extends StatelessWidget {
final List<String> numbers = [
'Soft Music',
'Meditation',
'Pray',
'Breathing',
'Relex'
];
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(right: 10, left: 10, top: 350),
height: MediaQuery.of(context).size.height * 0.3,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: numbers.length,
itemBuilder: (context, index) {
return Container(
width: 200,
margin: const EdgeInsets.only(right: 10),
child: RaisedButton(
color: Colors.brown,
child: Container(
child: Center(
child: Text(
numbers[index].toString(),
style: TextStyle(color: Colors.white, fontSize: 30.0),
)),
),
onPressed: () {
activityVideo(context);
//alertDialog to show a video
},
));
}));
}
This is my code for a alertDialog. This dialog i plan to show a video clip.
void activityVideo(BuildContext context){
var alertDialog = AlertDialog(
title: Text("videoclip"),
actions: <Widget>[
FlatButton(
child: Text('Rate'),
onPressed: () {
rateVideo(context);
}),
FlatButton(
child: Text('Finish'),
onPressed: () {
Navigator.of(context).pop();
}),
],
);
showDialog(context: context,
builder: (BuildContext context){
return alertDialog;
}
);
}
Cloud you show me an example the way to show the video. Or if there are any good ways to show the video instead this way you can suggest me. Thank you so much.
here is a picture of my app to make you clearer. This is my page if you click to activity it will popup the video cilp.
home page
This is a dialog that i plan to show a video.
alertDialog
AlertDialog has a content field that you can easily send a widget to it.check document for a simple example. Furthermore, for showing the video you use video_player package. for a simple tutorial check this post published by flutter team.
Im writing a simple gamebook game in flutter with menu, game and options route. In option route there is button that on pressed should delete all saved games.
Right at this moment Im loading saved games on application launch from SharedPreferences. Right after loading them I set up boolean _savedGame that im using in 'Continue' button in menu route and 'Delete saved games' button in options route to activate or deactivate them. The whole problem is - i dont know how to change variables in menu route from option route. When im creating option route I give it _savedGame so that it knows if it should render active or deactivated button.
PS. Yes, I know that right now im sending option route a copy of _savedGame variable.
Menu route option page button.
RaisedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OptionsPage(_savedGame),
),
),
Option page
class OptionsPageState extends State<OptionsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Options",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blueGrey[900],
),
body: Container(
alignment: Alignment.center,
color: Colors.cyan,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child:
Text('Delete saved games', style: TextStyle(fontSize: 40)),
onPressed:
widget.isGameSaved ? () => _showWarning(context) : null,
),
const SizedBox(height: 30),
RaisedButton(
child: Text('Back', style: TextStyle(fontSize: 40)),
onPressed: () {
Navigator.pop(context);
},
),
])),
),
);
}
Future<void> _showWarning(BuildContext context) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Are you sure you want to delete saved game?'),
actions: <Widget>[
FlatButton(
child: Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('Yes'),
onPressed: () {
saveGame('empty');
Navigator.of(context).pop();
setState(() {
widget.isGameSaved = false;
});
},
),
],
);
},
);
}
}
How do I "setState" for variables in different routes?
What you could do is have an InheritedWidget (call it say GameStateWidget) above your Navigator (or MaterialApp if you're using its navigator). In the InheritedWidget have a ValueNotifier, say savedGame that has the value you want to share.
Then in the route where you need to set the value
GameStateWidget.of(context).savedGame.value = ...
And in the route where you need the value
ValueListenableBuilder(
valueListenable: GameStateWidget.of(context).savedGame,
builder: (context, savedGameValue, child) => ...
)
I have a Scaffold with a simple Drawer in which I show a menu where a user can press a button. When this button is pressed I want to display a SnackBar, but the SnackBar is always displayed behind the Drawer. Is there some way to show it in front of the Drawer?
The drawer's code looks like:
class MyDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.lock_open),
title: Text('Click Me'),
onTap: () {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(
'Test.',
)));
},
),
],
),
);
}
}
and it is used directly in the Scaffold:
return Scaffold(
drawer: MyDrawer(),
[...]
They said Drawer must be on the top of UI under MaterialDesign rules. But if you wanna such behaviour too much you can write own SnackBar.
static void showSnackBarAsBottomSheet(BuildContext context, String message)
{
showModalBottomSheet<void>(
context: context,
barrierColor: const Color.fromRGBO(0, 0, 0, 0),
builder: (BuildContext context) {
Future.delayed(const Duration(seconds: 5), () {
try {
Navigator.pop(context);
} on Exception {}
});
return Container(
color: Colors.grey.shade800,
padding: const EdgeInsets.all(12),
child: Wrap(children: [
Text(
message,
style:
GoogleFonts.robotoCondensed().copyWith(color: Colors.white),
)
]));
},
);
}
I've solved it by adding one more Scaffold inside Drawer and making its background transparent:
return Scaffold(
drawer: Scaffold(
backgroundColor: Colors.transparent,
body: MyDrawer(),
[...]