I would like to show CupertinoPicker, when some button is pressed.
However I have no idea where I should implement CupertinoPicker.
Following code is sample of code which I don't know where I write to call.
showCupertinoModalPopup<String>(
context: context,
builder:(BuildContext context){
return _buildBottomPicker(CupertinoPicker(
onSelectedItemChanged: (value){
setState((){
selectedValue = value;
});
},
itemExtent: 32.0,
children: const[
Text('Item01'),
Text('Item02'),
Text('Item03'),
],
));
},
);
Here is the complete workable demo for launching cupertino picker when a button is pressed. Hope this solves your query.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: WeightSelect(),
debugShowCheckedModeBanner: false,
);
}
}
class WeightSelect extends StatefulWidget {
#override
_WeightSelectState createState() => _WeightSelectState();
}
class _WeightSelectState extends State<WeightSelect> {
int selectedValue;
showPicker() {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return CupertinoPicker(
backgroundColor: Colors.white,
onSelectedItemChanged: (value) {
setState(() {
selectedValue = value;
});
},
itemExtent: 32.0,
children: const [
Text('Item01'),
Text('Item02'),
Text('Item03'),
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Cupertino picker demo"),
),
body: Column(
children: <Widget>[
const SizedBox(height: 10.0),
Text("Selected: $selectedValue"),
const SizedBox(height: 10.0),
Center(
child: RaisedButton(
onPressed: showPicker,
child: Text("Show picker"),
),
),
],
),
);
}
}
It should be written when you want to open a popup or alertdialog with iOS cupertino style.
You can view the demo here :
http://flutterdevs.com/blog/know-your-widgets-1-cupertino-ios-style-actionsheet-in-flutter/
It may be displayed on button click when you need some confirmation or direction from the user.
Related
I want to display notifications that are being processed by a provider on an open gRPC stream. This is handled by notificationProvider.dart:
if (notification.type == 0) {
showOverlayNotification(notification);
} else {
notificationList.add(notification);
notifyListeners();
}
showOverlayNotification() then displays custom notification Widget OverlayNotification() on top of the current screen that user is in, like:
showOverlayNotification() async {
OverlayState? overlayState = Overlay.of(**context**);
OverlayEntry overlayEntry = OverlayEntry(builder: (context) {
return Positioned.fill(child: OverlayNotification());
});
overlayState?.insert(overlayEntry);
}
Now the problem is that I don't know how to get to the current context the user is in?
Android was pretty straightforward with this, but I can't seem to find this in Flutter..
How do I display overlay widget to a current context?
Do I have to keep track of it in a global variable in the end?
Can I find it through NamedRoutes?
can do something like this, fyi if you don't want to use navigator to pop current view you can create a navigator key as shown here
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
_buildPopupMessage(BuildContext context){
return Center(
child: IconButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return FittedBox(
fit: BoxFit.scaleDown,
child: AlertDialog(
title: Text(
'title text',
textAlign: TextAlign.center,
),
content: Text('message text here',
textAlign: TextAlign.center),
actions: <Widget>[
TextButton(
onPressed: () {
debugPrint('closed pressed');
Navigator.pop(context);
},
child: Text('close'),
)
],
),
);
},
);
},
icon: Icon(
Icons.live_help,
),
),
);
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body:_buildPopupMessage(context),
);
}
}
I have TestApp, where I have SplitView with 2 horizontal Containers. By clicking button in the first container on the left(blue) I want to show new page (DetailPage widget) but not all over the page, but only in the first Container. Now it shows on the whole screen. What is a best approach to do it?
import 'package:flutter/material.dart';
import 'package:split_view/split_view.dart';
void main() {
runApp(MaterialApp(
title: 'Test',
home: TestApp(),
));
}
class TestApp extends StatelessWidget {
const TestApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SplitView(
children: [
Container(
color: Colors.blue,
child: ElevatedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage()));
},
child: const Text('CLICK')),
),
Container(color: Colors.yellow),
],
viewMode: SplitViewMode.Horizontal,
indicator: SplitIndicator(viewMode: SplitViewMode.Horizontal),
activeIndicator: SplitIndicator(
viewMode: SplitViewMode.Horizontal,
isActive: true,
),
controller: SplitViewController(limits: [null, WeightLimit(max: 1)]),
),
);
}
}
class DetailPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('')), body: Container(color: Colors.red));
}
}
When pushing a new page you will be overriding the old one, meaning the new page will not have a spiltView, the best way to do this is by changing the widget displayed inside of the splitView like this :
import 'package:flutter/material.dart';
import 'package:split_view/split_view.dart';
void main() {
runApp(MaterialApp(
title: 'Test',
home: TestApp(),
));
}
class TestApp extends StatefulWidget { // I have already changed the widgte to stateful here
const TestApp({Key? key}) : super(key: key);
#override
_TestAppState createState() => _TestAppState();
}
class _TestAppState extends State<TestApp> {
#override
Widget build(BuildContext context) {
bool Bool;
return MaterialApp(
home: SplitView(
children: [
if (Bool == false){
Container(
color: Colors.blue,
child: ElevatedButton(
onPressed: () {
setState(() {
Bool = !Bool; // this the method for inverting the boolean, it just gives it the opposite value
});
},
child: const Text('CLICK')),
),
}
else{
DetailPage()
},
Container(color: Colors.yellow),
],
viewMode: SplitViewMode.Horizontal,
indicator: SplitIndicator(viewMode: SplitViewMode.Horizontal),
activeIndicator: SplitIndicator(
viewMode: SplitViewMode.Horizontal,
isActive: true,
),
controller: SplitViewController(limits: [null, WeightLimit(max: 1)]),
),
);
}
}
class DetailPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('')), body: Container(color: Colors.red));
}
}
Above I defined a bool called Bool, when rendering the page it checks if Bool is false, in that case it returns the blue widget, if it is true then it returns the red one, and when you click on the button it inverts the bool and updates the page.
Please note that for updating the page you have to use setState which rebuilds the widget, and to use it you have to use a stateful widget since stateless widget is static and cannot be changed.
Also I haven't tested the code because I don't have split_view package, but you should be able to copy and paste it just fine, if you get any errors please let me know.
When you use Navigator.push your routing to a new page and creating a new state. I think you should use showGeneralDialog instead.
showGeneralDialog(
context: context,
pageBuilder: (BuildContext context,
Animation<double> animation, Animation<double> pagebuilder) {
return Align(
alignment: Alignment.centerLeft,
child: Card(
child: Container(
alignment: Alignment.topLeft,
color: Colors.amber,
//show half the screen width
width: MediaQuery.of(context).size.width / 2,
child: IconButton(
icon: const Icon(Icons.cancel),
onPressed: () {
Navigator.pop(context);
}))),
);
});
try to create new Navigator within Container:
GlobalKey<NavigatorState> _navKey = GlobalKey();
home: SplitView(
children: [
Container(
child: Navigator(
key: _navKey,
onGenerateRoute: (_) => MaterialPageRoute<dynamic>(
builder: (_) {
return Container(
color: Colors.blue,
child: ElevatedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage()));
},
child: const Text('CLICK')),
);
},
),
),),
I have an alert dialog that displays a series of check boxes.
I am trying to ensure that if at least one of the checkboxes is selected, the confirm button is enabled, otherwise, if no checkbox is selected, it appears as inactive.
I have a parent and a child widget, both statefull. In one of them I have the button that should be enabled / disabled, and in the other one I have the content of the alert dialog.
The challenge for me has been to notify the parent widget from the child widget, that the flag variable with which I determine whether the button should be active or not, has been updated.
I have tried sending a function to the child widget that it executes, also with ValueSetter and ValueChanged, but so far without success.
If after activating or inactivating one of the checkboxes, I do a hot reload, the button is also updated. So I think it may be something with setState that I am not taking into account.
This is what I have done so far, ready to copy and paste into dartPad.
Thanks for your help.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: FrequencySelectionPage(),
),
),
);
}
}
class FrequencySelectionPage extends StatefulWidget {
FrequencySelectionPage();
#override
_FrequencySelectionPageState createState() => _FrequencySelectionPageState();
}
class _FrequencySelectionPageState extends State<FrequencySelectionPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListTile(
leading: Icon(Icons.calendar_today),
title: Text('Some days of the week'),
trailing: Icon(Icons.keyboard_arrow_right_rounded),
onTap: () {
_showDialog(context);
}
),),
);
}
void _showDialog(BuildContext context) {
final double screenSize = MediaQuery.of(context).size.height;
bool? canConfirm;
void setCanConfirm(bool value) {
setState(() {
canConfirm = value;
});
}
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Choose days"),
content: Container(
width: 200,
height: screenSize * 0.60,
child: ShowAlertContent(
setCanConfirm: setCanConfirm),
),
actions: <Widget>[
SizedBox(
width: screenSize * 0.50,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
SizedBox(
height: 20.0,
width: 20.0,
),
ElevatedButton(
child: Text('Confirm'),
onPressed: (canConfirm == false)
? null
: () {
Navigator.of(context).pop();
},
),
],
),
)
],
);
},
);
}
}
class ShowAlertContent extends StatelessWidget {
final ValueSetter<bool> setCanConfirm;
const ShowAlertContent(
{required this.setCanConfirm});
#override
Widget build(BuildContext context) {
return ShowSomeWeekDaysOptionContent(setCanConfirm: setCanConfirm);
}
}
class ShowSomeWeekDaysOptionContent extends StatefulWidget {
final ValueChanged<bool> setCanConfirm;
const ShowSomeWeekDaysOptionContent({required this.setCanConfirm});
#override
_ShowSomeWeekDaysOptionContentState createState() =>
_ShowSomeWeekDaysOptionContentState();
}
class _ShowSomeWeekDaysOptionContentState
extends State<ShowSomeWeekDaysOptionContent> {
Map<String, bool> days = {
'Day1': false,
'Day2': false,
'Day3': false,
'Day4': false,
'Day5': false,
'Day6': false,
'Day7': false
};
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ListView(
padding: EdgeInsets.all(8.0),
children: days.keys.map(
(day) {
return StatefulBuilder(builder:
(BuildContext context, StateSetter setCheckboxState) {
return CheckboxListTile(
title: Text(day),
value: days[day],
onChanged: (bool? value) {
setState(() {});
setCheckboxState(() {
days[day] = value!;
if (days.containsValue(true)) {
widget.setCanConfirm(true);
} else {
widget.setCanConfirm(false);
}
});
},
);
});
},
).toList(),
),
),
],
);
}
}
In your example you need something which rebuilds the button, when the value of canConfirm changes. You could use a ValueListenableBuilder. Therefore you have to make canConfirm a ValueNotifier.
Here is the working example:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: FrequencySelectionPage(),
),
),
);
}
}
class FrequencySelectionPage extends StatefulWidget {
FrequencySelectionPage();
#override
_FrequencySelectionPageState createState() => _FrequencySelectionPageState();
}
class _FrequencySelectionPageState extends State<FrequencySelectionPage> {
late ValueNotifier<bool> canConfirm;
#override
void initState() {
canConfirm = ValueNotifier(false);
super.initState();
}
void setCanConfirm(bool value) {
canConfirm.value = value;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListTile(
leading: Icon(Icons.calendar_today),
title: Text('Some days of the week'),
trailing: Icon(Icons.keyboard_arrow_right_rounded),
onTap: () {
_showDialog(context);
}),
),
);
}
void _showDialog(BuildContext context) {
final double screenSize = MediaQuery.of(context).size.height;
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Choose days"),
content: Container(
width: 200,
height: screenSize * 0.60,
child: ShowAlertContent(setCanConfirm: setCanConfirm),
),
actions: <Widget>[
SizedBox(
width: screenSize * 0.50,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
SizedBox(
height: 20.0,
width: 20.0,
),
ValueListenableBuilder<bool>(
valueListenable: canConfirm,
builder: (context, value, child) {
return ElevatedButton(
child: Text('Confirm'),
onPressed: (value == false)
? null
: () {
Navigator.of(context).pop();
},
);
},
),
],
),
)
],
);
},
);
}
}
class ShowAlertContent extends StatelessWidget {
final ValueSetter<bool> setCanConfirm;
const ShowAlertContent({required this.setCanConfirm});
#override
Widget build(BuildContext context) {
return ShowSomeWeekDaysOptionContent(setCanConfirm: setCanConfirm);
}
}
class ShowSomeWeekDaysOptionContent extends StatefulWidget {
final ValueChanged<bool> setCanConfirm;
const ShowSomeWeekDaysOptionContent({required this.setCanConfirm});
#override
_ShowSomeWeekDaysOptionContentState createState() =>
_ShowSomeWeekDaysOptionContentState();
}
class _ShowSomeWeekDaysOptionContentState
extends State<ShowSomeWeekDaysOptionContent> {
Map<String, bool> days = {
'Day1': false,
'Day2': false,
'Day3': false,
'Day4': false,
'Day5': false,
'Day6': false,
'Day7': false
};
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: ListView(
padding: EdgeInsets.all(8.0),
children: days.keys.map(
(day) {
return StatefulBuilder(builder:
(BuildContext context, StateSetter setCheckboxState) {
return CheckboxListTile(
title: Text(day),
value: days[day],
onChanged: (bool? value) {
setCheckboxState(() {
days[day] = value!;
if (days.containsValue(true)) {
widget.setCanConfirm(true);
} else {
widget.setCanConfirm(false);
}
});
},
);
});
},
).toList(),
),
),
],
);
}
}
I don’t know about your case but ummmm.. I think this one maybe a lot easier
`bool _isChecked = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Checkbox(
value: _isChecked,
onChanged: (value) {
setState(() {
_isChecked = value;
});
},
),
ElevatedButton(
child: Text('Button'),
onPressed: (){
if(_isChecked){
print('CHeckbox is checked');
}else{
print('CHeckbox is not checked');
}
},
),
],
);
}`
I want to intercept the back-button of the soft keyboard in flutter. So when I want to close the keyboard by pressing the back-button I want an additional function to be called.
How can I do that?
Keyboard Back button
you can use the keyboard_visibility package to achieve this.
Working Example
the following code displays a SnackBar once the keyboard is dismissed.
import 'package:flutter/material.dart';
import 'package:keyboard_visibility/keyboard_visibility.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
GlobalKey<ScaffoldState> _key;
#override
void initState() {
super.initState();
_key = GlobalKey<ScaffoldState>();
KeyboardVisibilityNotification().addNewListener(
onHide: () {
_key.currentState.showSnackBar(
SnackBar(
content: Text("Keyboard closed"),
),
);
},
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _key,
body: Center(
child: TextField(),
),
),
);
}
}
you can use the https://pub.dev/packages/flutter_keyboard_visibility package to achieve this.
import 'package:flutter/material.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:flutter_keyboard_visibility_example/keyboard_dismiss_demo.dart';
import 'package:flutter_keyboard_visibility_example/provider_demo.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Demo(),
);
}
}
class Demo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return KeyboardDismissOnTap(
child: Scaffold(
appBar: AppBar(
title: Text('Keyboard Visibility Example'),
),
body: Center(
child: Padding(
padding: EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProviderDemo()),
);
},
child: Text('Provider Demo'),
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => KeyboardDismissDemo()),
);
},
child: Text('KeyboardDismiss Demo'),
),
Spacer(),
TextField(
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Input box for keyboard test',
),
),
Container(height: 60.0),
KeyboardVisibilityBuilder(builder: (context, visible) {
return Text(
'The keyboard is: ${visible ? 'VISIBLE' : 'NOT VISIBLE'}',
);
}),
Spacer(),
],
),
),
),
),
);
}
}
I am trying to show an Alert Dialog on press of a button in Flutter.
Following is my code
main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Different Widgets",
debugShowCheckedModeBanner: false,
home: showAlertDialog()
);
}
void _dialogResult(String value) {
if (value == "YES") {
print("YES");
} else {
print("NO");
}
Navigator.pop(context);
}
Widget showAlertDialog() {
TextEditingController textEditingController = TextEditingController();
return Scaffold(
appBar: AppBar(
title: Text("Different Widgets"),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
TextField(
controller: textEditingController,
),
RaisedButton(
onPressed: () {
print("Hi");
AlertDialog dialog = AlertDialog(
title: Text("Hi"),
content: Text(
textEditingController.text,
style: TextStyle(fontSize: 30.0),
),
actions: <Widget>[
FlatButton(
onPressed: () {
_dialogResult("YES");
},
child: Text("YES")),
FlatButton(
onPressed: () {
_dialogResult("NO");
},
child: Text("NO")),
],
);
showDialog(context: context, builder: (BuildContext context) => dialog);
},
child: Text("Click Me"),
)
],
),
),
),
);
}
What does this has to do with Localisation, I cannot follow. I did the same steps as per the docs. I am able to see the button but on click of that button I keep getting error. I tried writing print statement inside of button click and the print statement appears in the log, definitely something wrong with AlertDialog.
You may get No MaterialLocalizations found error while showing dialog using showDialog() class in Flutter. The issue is putting child widget on home property of MaterialApp() widget without creating new widget class.
One way to solve is putting MaterialApp() inside runApp() and create new class for home property.
import 'package:flutter/material.dart';
main() {
runApp(
MaterialApp(
home: MyApp(),
title: "Different Widgets",
debugShowCheckedModeBanner: false,
),
);
}
/*
place MaterialApp() widget on runApp() and create
new class for its 'home' property
to escape 'No MaterialLocalizations found' error
*/
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return showAlertDialog();
}
void _dialogResult(String value) {
if (value == "YES") {
print("YES");
} else {
print("NO");
}
Navigator.pop(context);
}
Widget showAlertDialog() {
TextEditingController textEditingController = TextEditingController();
return Scaffold(
appBar: AppBar(
title: Text("Different Widgets"),
),
body: Container(
child: Center(
child: Column(
children: <Widget>[
TextField(
controller: textEditingController,
),
RaisedButton(
onPressed: () {
print("Hi");
AlertDialog dialog = AlertDialog(
title: Text("Hi"),
content: Text(
textEditingController.text,
style: TextStyle(fontSize: 30.0),
),
actions: <Widget>[
FlatButton(
onPressed: () {
_dialogResult("YES");
},
child: Text("YES")),
FlatButton(
onPressed: () {
_dialogResult("NO");
},
child: Text("NO")),
],
);
showDialog(
context: context,
builder: (BuildContext context) => dialog);
},
child: Text("Click Me"),
)
],
),
),
),
);
}
}