Flutter: Close DropdownButton (DropdownMenu) - flutter

Is there a way to close the selection menu of a DropdownButton containing all the DropdownMenuItems when an onTap function is executed (GestureDetector inside a DropdownMenuItem)?
Here is my implementation of the approach of Alperen Baskaya (in a slightly reduced version so that it is understandable). This approach however does not work yet and I am not sure whether it is because I have implemented it incorrectly or because the approach does not work for my problem.
class _BoatSelectionState extends State<BoatSelection> {
FocusNode focusNode;
#override
void initState() {
super.initState();
focusNode = FocusNode();
}
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child:
DropdownButtonHideUnderline(
child: DropdownButton<Boat>(
focusNode: focusNode,
icon: Icon(
Icons.keyboard_arrow_down_rounded,
color: Colors.black,
),
isExpanded: true,
value: selectedBoat,
onChanged: (Boat _boat) => Provider.of<BoatStreamsCubit>(context, listen: false).setBoat(_boat),
selectedItemBuilder: (BuildContext context) {
return widget.boats.map<Widget>((Boat boat) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BoatClassLogo(boat: boat),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: DesignValues.paddingMd),
child: BoatInformation(boat: boat),
),
),
],
);
}).toList();
},
items: widget.boats.map<DropdownMenuItem<Boat>>((Boat _boat) {
return DropdownMenuItem<Boat>(
value: _boat,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: DesignValues.paddingMd),
child: BoatClassLogo(boat: _boat),
),
Expanded(
child: BoatInformation(boat: _boat),
),
GestureDetector(
onTap: () {
focusNode.unfocus();
Navigator.push(context, MaterialPageRoute(builder: (context) => BoatForm(CreationState.edit, _boat)));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Icon(
Icons.edit,
color: AppColors.primary,
),
),
),
],
),
);
}).toList(),
),
),
),
],
);
}
}

I looked up the internal implementation of DropdownMenu in dart.
The popover for DropdownMenu is created by using Navigator.push(). It waits for the user to click an item and returns the value with Navigator.pop(). So we can pop the popover manually by getting the dropdown's context via a GlobalKey.
late GlobalKey dropdownKey;
#override
void initState() {
super.initState();
dropdownKey = GlobalKey();
}
...
DropdownButton<Boat>(
key: dropdownKey,
...)
And remove it using Navigator.pop()
GestureDetector(
onTap: () {
Navigator.pop(dropdownKey.currentContext);
Full code:
class _BoatSelectionState extends State<BoatSelection> {
GlobalKey dropdownKey;
#override
void initState() {
super.initState();
dropdownKey = GlobalKey(); // Init GlobalKey, allows to close the DropdownButton
}
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child:
DropdownButtonHideUnderline(
child: DropdownButton<Boat>(
key: dropdownKey,
icon: Icon(
Icons.keyboard_arrow_down_rounded,
color: Colors.black,
),
isExpanded: true,
value: selectedBoat,
onChanged: (Boat _boat) => Provider.of<BoatStreamsCubit>(context, listen: false).setBoat(_boat),
selectedItemBuilder: (BuildContext context) {
return widget.boats.map<Widget>((Boat boat) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BoatClassLogo(boat: boat),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: DesignValues.paddingMd),
child: BoatInformation(boat: boat),
),
),
],
);
}).toList();
},
items: widget.boats.map<DropdownMenuItem<Boat>>((Boat _boat) {
return DropdownMenuItem<Boat>(
value: _boat,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: DesignValues.paddingMd),
child: BoatClassLogo(boat: _boat),
),
Expanded(
child: BoatInformation(boat: _boat),
),
GestureDetector(
onTap: () {
Navigator.pop(dropdownKey.currentContext); // Closes the dropdown
Navigator.push(context, MaterialPageRoute(builder: (context) => BoatForm(CreationState.edit, _boat)));
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Icon(
Icons.edit,
color: AppColors.primary,
),
),
),
],
),
);
}).toList(),
),
),
),
],
);
}
}

If I got you right you can use focus node for dropdown menu.
FocusNode dropdown;
Initializing in initstate is needed;
dropdown = FocusNode();
child: DropdownButtonHideUnderline(
child: DropdownButton <String>(
focusNode: dropdown,
Then when you may think to close this menu execute in ontap;
dropdown.unfocus();

Related

FlutterError (No Material widget found. IconButton widgets require a Material widget ancestor

When I used
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
GroupAddPosts(groupType: widget.groupType),
),
);
},
to change page then I got this error FlutterError (No Material widget found. IconButton widgets require a Material widget ancestor.
But I had did added it, my IconButton has Center on above
#override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context).getUser;
final width = MediaQuery.of(context).size.width;
String value;
return _selected == "0"
? Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(
Icons.photo,
size: 40,
),
onPressed: () => selectImage(),
),
Text(
'max: 9 photos',
style: TextStyle(color: Colors.white),
),
],
),
),
So, where has issues?
And I also set
#override
void initState() {
super.initState();
setState(() {
_selected = "0";
});
}
Still got error.... where has error step and how to fix this problem?
just wrap it with Scaffold or Material widget.
Scaffold(body:Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: const Icon(
Icons.photo,
size: 40,
),
onPressed: () => selectImage(),
),
Text(
'max: 9 photos',
style: TextStyle(color: Colors.white),
),
],
),
),

Auto landscape when the user click the full screen video using flutter

i hope the title is enough to understand my problem is, story line: When the user click full screen. the video automatic landscape. How? please help me
Container(
child: Column(children: <Widget>[
Expanded(
child: Container(
margin: const EdgeInsets.all(0.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent)),
child: InAppWebView(
initialUrl:
"https://ip-address/play.html?name=123456789",
initialHeaders: {},
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart:
(InAppWebViewController controller, String url) {
setState(() {
this.url = url;
});
},
onLoadStop: (InAppWebViewController controller,
String url) async {
setState(() {
this.url = url;
});
},
onProgressChanged:
(InAppWebViewController controller, int progress) {
setState(() {
this.progress = progress / 100;
});
},
),
),
),
])),
dependencies: auto_orientation: ^2.0.0
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:auto_orientation/auto_orientation.dart';
void main() {
runApp(
AutoOrientationDemo(),
);
}
class AutoOrientationDemo extends StatefulWidget {
AutoOrientationDemo({this.title = 'Auto Orientation Demo'});
final String title;
#override
State<StatefulWidget> createState() {
return _AutoOrientationDemoState();
}
}
class _AutoOrientationDemoState extends State<AutoOrientationDemo> {
TargetPlatform? _platform;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: widget.title,
theme: ThemeData.light().copyWith(
platform: _platform ?? Theme.of(context).platform,
),
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextButton(
onPressed: () {
AutoOrientation.portraitDownMode();
},
child: Padding(
child: Text("Portrait UPSIDE Down"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: TextButton(
onPressed: () {
AutoOrientation.fullAutoMode();
},
child: Padding(
child: Text("All modes"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: TextButton(
onPressed: () {
AutoOrientation.landscapeAutoMode();
},
child: Padding(
child: Text("Landscape auto"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: TextButton(
onPressed: () {
AutoOrientation.portraitAutoMode();
},
child: Padding(
child: Text("Portrait auto"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: TextButton(
onPressed: () {
AutoOrientation.landscapeLeftMode();
},
child: Padding(
child: Text("Landscape left mode"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: TextButton(
onPressed: () {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
AutoOrientation.landscapeRightMode();
},
child: Padding(
child: Text("Landscape right mode"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: TextButton(
onPressed: () {
AutoOrientation.portraitUpMode();
},
child: Padding(
child: Text("Portrait up mode"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
Expanded(
child: TextButton(
onPressed: () {
AutoOrientation.portraitDownMode();
},
child: Padding(
child: Text("Portrait down mode"),
padding: EdgeInsets.symmetric(vertical: 16.0),
),
),
),
],
)
],
),
),
);
}
}
This Will Help You For Auto Screen Orientation based on your content
You can use JavaScript channel to get notifications from the web view. See a section on channels here:
https://medium.com/flutter-community/inappwebview-the-real-power-of-webviews-in-flutter-c6d52374209d
Then in your HTML/JavaScript, listen to full the screen event on your video object and send it to the JavaScript channel to be handled in Flutter app.

Flutter item not updating in widget when delete need to come back to see changes

I have a simple cart page I am showing products on the cart page. The issue is when I am deleting an item it's deleting but in the widget, it's not deleting I need to go back and come again to show the changes. I try to rise setState also but not working.
My code
class _CartPageState extends State<CartPage> {
num amount = 0;
bool checkLogin = false;
void navigateToAddressPage() {
Get.to(AddressPage());
}
check() async {
final storage = new FlutterSecureStorage();
String imi = await storage.read(key: "imei");
print(imi);
if (imi == "loginhuavaha") {
setState(() {
this._query();
checkLogin = true;
});
}
}
#override
void initState() {
setState(() {
this.check();
});
}
List<Widget> textWidgetList = List<Widget>();
void _query() async {
print('cart');
final dbHelper = DatabaseHelper.instance;
final allRows = await dbHelper.queryAllRows();
allRows.forEach((row) {
amount += double.parse(row['price']);
print(amount);
print(row);
});
for (int i = 0; i < allRows.length; i++) {
textWidgetList.add(Card(
elevation: 5.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
margin: EdgeInsets.symmetric(vertical: 8.0),
child: Container(
width: double.infinity,
height: 120.0,
padding: EdgeInsets.all(12.0),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12.0),
child: Image.network(allRows[i]['image'],
width: 100, height: 100)),
SizedBox(width: 12.0),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
allRows[i]['title'],
textAlign: TextAlign.start,
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
),
SizedBox(width: 5.0),
Row(
children: [
GestureDetector(
onTap: () async {
print('delete');
final id = await dbHelper.queryRowCount();
print(id);
final rowsDeleted = await dbHelper.delete(
id, allRows[i]['id']);
print('deleted $rowsDeleted row(s): row $id');
setState(() {
});
},
child: Icon(
FlutterIcons.delete_outline_mco,
),
)
],
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
allRows[i]['price'],
),
),
// Counter(),
],
),
],
),
),
)
],
),
),
));
}
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(context),
body: checkLogin
? Container(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Column(children: textWidgetList),
],
),
),
)
: Center(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(child: Text('Your are not login')),
SizedBox(height: 10),
SizedBox(
width: 85.0,
height: 50.0,
child: RaisedButton(
color: Theme.of(context).primaryColor,
elevation: 0.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Text(
'LOGIN',
style: Theme.of(context).textTheme.button,
).tr(),
onPressed: () {
Get.offAll(SignInPage());
},
),
),
])),
),
);
}
You can see I have added a comment in my code I delete the product and it actually deleted from database but state isn't changing of widget -_-
I think what you need here is the Provider package. Provider makes state management easier a lot. Just define a model class that extends ChangeNotifier and then wrap your widgets with ChangeNotifierProvider<Model_class_name>. To access the fields Use Provider.of(context).var or Provider.of(context).function
First of all you need to put textWidgetList in the setState since you manipulate those Widgets I guess. Secondly you have to put a key to those Widgets due to how Flutter handles elements in a list on the UI.Have a look at this page https://medium.com/flutter/keys-what-are-they-good-for-13cb51742e7d
Its Simple Man
Once the item is removed
use setState((){})
setState(() {
//Inside setState Clear the allrows list
allrows.clear();
//Then get the allrows again so that the deleted data will not be shown
allRows = await dbHelper.queryAllRows();
});
setState rebuilds your widgets

I want to delete selected data from the list using the delete button in action bar

I'm new to flutter and I want to delete the selected values from the
list,but I don't know how to delete selected Items,can anyone help?
I have taken icon button in Appbar and I tried to setState in it by
using the .removelast() command,but I want to select the Item then
delete it.
Code :
class DemoPage extends State<MyHomePage> {
TextEditingController Controller = TextEditingController();
List<String> msg = List();
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Demo_App'),
actions: <Widget>[
IconButton(icon: Icon(Icons.delete),
onPressed: (){
setState(() {
msg.removeLast();
});
}),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
alignment: Alignment.topLeft,
margin: EdgeInsets.only(right: 150.0,top: 10.0,left: 8.0),
child:TextField(
controller: Controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'please enter your name',
),
),
),
Container(
alignment: Alignment.topRight,
margin: EdgeInsets.only(left: 250.0,right: 10.0),
child: RaisedButton(
onPressed: () {
setState(() {
msg.add(Controller.text);
Controller.clear();
});
},
child: Text('Add'),
),
),
Expanded(
flex: 2,
child: Container(
child: Card(
margin: EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: msg.length,
itemBuilder: (context, index){
if(index.isInfinite){
return Divider();
}
return ListTile(
title: Text(msg[index]),
);
},),
),
)),
],
),
);
}
}
I want to select the data and then delete it using the icon Button in
the AppBar.
Lets assume you want to select your items by a single click.
Take a separate a list indexList and each time you select an item, you store the clicked index into indexList.
Then upon clicking delete button run a loop on indexList and remove items from your itemList using the stored indexes.
clean indexList
update your state
class DemoPage extends State<MyHomePage> {
TextEditingController Controller = TextEditingController();
List<String> msg = List();
List<int> selectedItems = List();
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Demo_App'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
setState(() {
msg.removeLast();
});
}),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
alignment: Alignment.topLeft,
margin: EdgeInsets.only(right: 150.0, top: 10.0, left: 8.0),
child: TextField(
controller: Controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'please enter your name',
),
),
),
Container(
alignment: Alignment.topRight,
margin: EdgeInsets.only(left: 250.0, right: 10.0),
child: RaisedButton(
onPressed: () {
setState(() {
msg.add(Controller.text);
Controller.clear();
});
},
child: Text('Add'),
),
),
Expanded(
flex: 2,
child: Container(
child: Card(
margin: EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: msg.length,
itemBuilder: (context, index) {
return new GestureDetector(
onLongPress: () {
if(selectedItems.contains(index))
selectedItems.remove(index);
else
selectedItems.add(index);
},
onTap: () {
if(selectedItems.contains(index))
selectedItems.remove(index);
else
selectedItems.add(index);
},
child: index.isInfinite
? Divider()
: ListTile(
title: Text(msg[index]),
));
}),
),
)),
],
),
);
}
void _deleteItems(){ // call _deleteItems() on clicking delete button
setState(() {
//set your state
for (final index in selectedItems)
msg.removeAt(index);
selectedItems.clear();
});
}
}

Is it possible to use a DropDownButton within an IconButton in Flutter?

Update:
#override
Widget build(BuildContext context) {
return new Container(
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Container(
height: 220.0,
width: MediaQuery.of(context).size.width,
child: new GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Column(
children: <Widget>[
SizedBox(height: 40.0),
Row(
children: <Widget>[
Expanded(
child: Stack(
children: [
Center(
child: Text(
'Profile',
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Lato',
color: Colors.white,
fontSize: 50.0,
fontWeight: FontWeight.w700,
),
),
),
Positioned(
right: 8,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 400)),
PopupMenuButton<String>(
icon: Icon(
Icons.settings,
color: Colors.white,
size: 30.0,
),
onSelected: choiceAction,
itemBuilder: (BuildContext context) {
return Constants.choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
),
),
],
),
),
],
),
I am trying to implement a DropDownButton inside the OnPressed command of an IconButton, so that when the icon is pressed, a drop down menu is shown.
Update: I've updated my code with the suggestion made, however the icon does not appear.
I'm not sure if this is a problem with my widget tree.
Updated Answer
Please check this code:
class DropdownMenu extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 400)),
PopupMenuButton<String>(
icon: Icon(Icons.settings),
onSelected: choiceAction,
itemBuilder: (BuildContext context) {
return Constants.choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
));
}
}
class Constants {
static const String FirstItem = 'First Item';
static const String SecondItem = 'Second Item';
static const String ThirdItem = 'Third Item';
static const List<String> choices = <String>[
FirstItem,
SecondItem,
ThirdItem,
];
}
void choiceAction(String choice) {
if (choice == Constants.FirstItem) {
print('I First Item');
} else if (choice == Constants.SecondItem) {
print('I Second Item');
} else if (choice == Constants.ThirdItem) {
print('I Third Item');
}
}
Note: This is not dropdown menu but i think this is what you want.
Old answer
You can try using showDialog
child: Row(
children: <Widget>[
IconButton(
icon: Icon(
Icons.settings,
color: Colors.black,
size: 30.0,
),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Country List'),
content: new ListView(
children: <Widget>[
new Column(
children: <Widget>[
new DropdownButton<String>(
items: <String>['A', 'B', 'C', 'D', 'E', 'F', 'G'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
),
],
),
],
),
);
});
})
],
)