How to fix sidebar when using Navigation.of.push on iPad - flutter

Sorry for my bad English.
Problem
I'm currently developing an application for iPad with Flutter.
It is only used on iPad, not on iPhone or Android.
I want to always display the sidebar where Items are arranged like BottomNavigationBar, but when using Navigator.of.push, moving screen with the sidebar disappeared.
What do I want to do
I wanna make the transition with the sidebar still displayed as in Twitter for iPad or Settings app for iPad, but if anyone knows how to do it, please let me know.
App top screen
Select item1 and push button
How can i set ios back button only on right screen like Settings App for iPad like this image?
I wanna create a UI like a Setting app for iPad.
Code
lib/main.dart
import 'package:flutter/material.dart';
import 'package:health_check/ui/master_detail_container.dart';
void main() => runApp(MyAppScreen());
class MyAppScreen extends StatefulWidget {
#override
_MyAppScreenState createState() => _MyAppScreenState();
}
class _MyAppScreenState extends State<MyAppScreen> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MasterDetailContainer(),
);
}
}
lib/ui/master_detail_container.dart
import 'package:flutter/material.dart';
import 'package:health_check/ui/item.dart';
import 'package:health_check/ui/item_details.dart';
import 'package:health_check/ui/item_listing.dart';
class MasterDetailContainer extends StatefulWidget {
#override
_ItemMasterDetailContainerState createState() =>
_ItemMasterDetailContainerState();
}
class _ItemMasterDetailContainerState extends State<MasterDetailContainer> {
Item _selectedItem;
Widget _sideBar() {
return Flexible(
flex: 1,
child: Material(
elevation: 4.0,
child: ItemListing(
itemSelectedCallback: (item) {
setState(() {
_selectedItem = item;
});
},
selectedItem: _selectedItem,
),
),
);
}
Widget _itemContent() {
return Flexible(
flex: 3,
child: ItemDetails(
item: _selectedItem,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
_sideBar(),
_itemContent(),
],
),
);
}
}
lib/ui/item_listing.dart
import 'package:flutter/material.dart';
import 'package:health_check/ui/item.dart';
import 'package:health_check/ui/item_details.dart';
class ItemListing extends StatelessWidget {
ItemListing({
#required this.itemSelectedCallback,
this.selectedItem,
});
final ValueChanged<Item> itemSelectedCallback;
final Item selectedItem;
#override
Widget build(BuildContext context) {
// return
return ListView(
children: items.map((item) {
return ListTile(
title: Text(item.title),
onTap: () => itemSelectedCallback(item),
selected: selectedItem == item,
);
}).toList(),
);
}
}
lib/ui/item_details.dart
import 'package:flutter/material.dart';
import 'package:health_check/ui/item.dart';
import 'package:health_check/ui/item1_screen.dart';
import 'package:meta/meta.dart';
class ItemDetails extends StatelessWidget {
ItemDetails({
#required this.item,
});
final Item item;
#override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
final Widget content = Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
child: Text("Button"),
color: Colors.orange,
textColor: Colors.white,
onPressed: () {
Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(builder: (context) => Item1Screen()));
},
),
Text(
item?.title ?? 'No item selected!',
style: textTheme.headline,
),
Text(
item?.subtitle ?? 'Please select one on the left.',
style: textTheme.subhead,
),
],
);
return Scaffold(
appBar: AppBar(
title: Text('Appbar'),
),
body: Center(child: content),
);
}
}
lib/ui/item1_screen.dart
import 'package:flutter/material.dart';
class Item1Screen extends StatelessWidget {
Item1Screen();
#override
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(
title: Text('Item1 detail'),
),
body: Center()
);
}
}
lib/ui/item.dart
import 'package:meta/meta.dart';
class Item {
Item({
#required this.title,
#required this.subtitle,
});
final String title;
final String subtitle;
}
final List<Item> items = <Item>[
Item(
title: 'Item 1',
subtitle: 'This is the first item.',
),
Item(
title: 'Item 2',
subtitle: 'This is the second item.',
),
Item(
title: 'Item 3',
subtitle: 'This is the third item.',
),
];

Related

Make bottomNavigationBar expand down to use whole screen in Flutter

I am new to Flutter and went on to do the codelabs - first flutter app
Since I'm learning Flutter to develop mobile apps, this tutorials use of NavigationRail isn't too good looking on a phone. I tried to switch it out for a BottomNavigationBar. When changing the background color of the navbar I noticed it doesnt expand to use the full screen. Is it always like this, or is there something making it display it this way in the code?Could'nt find any useful information about this case.
Is it possible to make the green background cover the, here black, area at the bottom of the screen?
Area under bar, white when debugging on real device, here it is black
The final code from the tutorial is poorly adjusted to:
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => MyAppState(),
child: MaterialApp(
title: 'Namer App',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
),
home: MyHomePage(),
),
);
}
}
class MyAppState extends ChangeNotifier {
var current = WordPair.random();
void getNext() {
current = WordPair.random();
notifyListeners();
}
var favorites = <WordPair>[];
void toggleFavorite() {
if (favorites.contains(current)) {
favorites.remove(current);
} else {
favorites.add(current);
}
notifyListeners();
}
}
class MyHomePage extends StatefulWidget {
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var selectedIndex = 0;
#override
Widget build(BuildContext context) {
Widget page;
switch(selectedIndex){
case 0:
page = GeneratorPage();
break;
case 1:
page = FavoritesPage();
break;
default:
throw UnimplementedError('no widget for $selectedIndex');
}
return LayoutBuilder(
builder: (context, constraints) {
return Scaffold(
body: Center(
child: page,
),
bottomNavigationBar: BottomNavigationBar (
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite),
label: 'Favorites',
),
],
currentIndex: selectedIndex,
onTap: _onItemTapped,
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
elevation: 0.0,
),
);
}
);
}
void _onItemTapped(int index){
setState(() {
selectedIndex = index;
});
}
}
class FavoritesPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var appState = context.watch<MyAppState>();
if (appState.favorites.isEmpty) {
return Center(
child: Text('No favorites yet.'),
);
}
return ListView(
children: [
Padding(
padding: const EdgeInsets.all(20),
child: Text('You have '
'${appState.favorites.length} favorites:'),
),
for (var pair in appState.favorites)
ListTile(
leading: Icon(Icons.favorite),
title: Text(pair.asLowerCase),
),
],
);
}
}
class GeneratorPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var appState = context.watch<MyAppState>();
var pair = appState.current;
IconData icon;
if (appState.favorites.contains(pair)) {
icon = Icons.favorite;
} else {
icon = Icons.favorite_border;
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BigCard(pair: pair),
SizedBox(height: 10),
Row(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton.icon(
onPressed: () {
appState.toggleFavorite();
},
icon: Icon(icon),
label: Text('Like'),
),
SizedBox(width: 10),
ElevatedButton(
onPressed: () {
appState.getNext();
},
child: Text('Next'),
),
],
),
],
),
);
}
}
class BigCard extends StatelessWidget {
const BigCard({
Key? key,
required this.pair,
}) : super(key: key);
final WordPair pair;
#override
Widget build(BuildContext context) {
var theme = Theme.of(context);
var style = theme.textTheme.displayMedium!.copyWith(
color: theme.colorScheme.onPrimary,
);
return Card(
color: theme.colorScheme.primary,
elevation: 10,
child: Padding(
padding: const EdgeInsets.all(20),
child: Text(pair.asLowerCase, style: style),
),
);
}
}
Tried changing elevation to 0.0, expandbody and what not. Nothing seems to be working here?
You can use SystemUiOverlayStyle class
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light
.copyWith(systemNavigationBarColor: Colors.greenAccent));
super.initState();
}

How do i print the value which is coming from modal bottom sheet to the main scaffold body in dart+flutter

ive created a text and icon button, onpressing that icon
modal bottom sheet gets generated, in that
and ive created a separate dart file with text field and a submit button
when giving an input on text field and after clicking on submit button the given input string will be printed below
atlast i called the function in first dart file
but i want the text to be printed on the main scaffold page.
Below is the main code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:practice1/StatefulModalbtn.dart';
void main() {
runApp(Modalbtn());
}
class Modalbtn extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Modal Bottom Test'),
),
body: Column(
children: <Widget>[Mymodal()],
),
),
);
}
}
class Mymodal extends StatelessWidget {
const Mymodal({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'Press the icon to select the Tractor model',
style: TextStyle(fontSize: 15),
),
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: <Widget>[StatefulModalbtn()],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
)
],
),
);
}
}
and below code is for creating a text field and submit button
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatefulWidget {
const StatefulModalbtn({Key? key}) : super(key: key);
#override
_StatefulModalbtnState createState() => _StatefulModalbtnState();
}
class _StatefulModalbtnState extends State<StatefulModalbtn> {
TextEditingController textController = TextEditingController();
String displayText = "";
#override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: textController,
maxLines: null,
),
ElevatedButton(
onPressed: () {
setState(() {
displayText = textController.text;
});
},
child: Text('Submit')),
Text(
displayText,
style: TextStyle(fontSize: 20),
),
],
);
}
}
and below is the output link
this is the output im achieving but i want the "Hello World" to be printed on top/main screen, right after the + add icon screen
How should i solve this ??
I just slightly edited your code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'main1.dart';
void main() {
runApp(MaterialApp(
home: Modalbtn(),
));
}
class Modalbtn extends StatefulWidget {
#override
_ModalbtnState createState() => _ModalbtnState();
}
class _ModalbtnState extends State<Modalbtn> {
String value = "0";
// Pass this method to the child page.
void _update(String newValue) {
setState(() => value = newValue);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 200,
child: Column(
children: [StatefulModalbtn(update: _update)],
),
);
});
},
icon: Icon(Icons.add),
iconSize: 20,
),
Text(
value,
style: TextStyle(fontSize: 40),
),
],
),
),
);
}
}
and the child class is
import 'package:flutter/material.dart';
class StatefulModalbtn extends StatelessWidget {
final ValueChanged<String> update;
StatefulModalbtn({required this.update});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => update("100"), // Passing value to the parent widget.
child: Text('Update (in child)'),
);
}
}

Flutter - New page route is only leading to a blank page

I've already created one page route, to the feed_page, but now, when going from feed_page to new_post_page, the new_post_page is just blank on the simulated phone.
Here's the obligatory code dump :)
In this first code dump (page of origin), I omitted the other contents of the appBar and the body of the scaffold:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:we_rise/post_card.dart';
import 'new_post_page.dart';
import 'constants.dart';
class FeedPage extends StatefulWidget {
#override
_FeedPageState createState() => _FeedPageState();
}
class _FeedPageState extends State<FeedPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
...
),
actions: <Widget>[
// PAGE ROUTE IN QUESTION
IconButton(
icon: const Icon(Icons.add_circle),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => NewPostPage()));
},
),
],
),
body: ListView.builder(
...
),
);
}
}
And then the problematic new page that is just showing up blank in the simulated phone:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'constants.dart';
class NewPostPage extends StatefulWidget {
#override
_NewPostPageState createState() => _NewPostPageState();
}
class _NewPostPageState extends State<NewPostPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xFFFFC033),
title: const Text('New Post'),
),
body: Expanded(
child: Column(
children: const <Widget>[
Text('Placeholder')
],
)
),
);
}
}
Problem is in body, Remove Expanded widget from body only keep Column widget and Run, set as below.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'constants.dart';
class NewPostPage extends StatefulWidget {
#override
_NewPostPageState createState() => _NewPostPageState();
}
class _NewPostPageState extends State<NewPostPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xFFFFC033),
title: const Text('New Post'),
),
body: Column(
children: const <Widget>[
Text('Placeholder')
],
),
);
}
}
Ex:
=> You are Remove Expanded Widigit
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'constants.dart';
class NewPostPage extends StatefulWidget {
#override
_NewPostPageState createState() => _NewPostPageState();
}
class _NewPostPageState extends State<NewPostPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xFFFFC033),
title: const Text('New Post'),
),
body: Column(
children: const <Widget>[
Text('Placeholder')
],
),
);
}
}

Why can't I display a list in rows in dropdown button in Flutter?

I want to show an icon and text as each item in a dropdown menu.
According to this answer https://stackoverflow.com/a/65831827/7870443 I tried. But my code is not working. I see an underline and dropdown button. But not clickable.
This is what I got.
I see an underline and dropdown button. But not clickable.
Below is the code I tried from that link
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html/html_parser.dart';
import 'package:flutter_html/style.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(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> {
String dropdownValue = 'Hillary';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: DropdownButton<String>(
items: <String>['Hillary', 'Joe', 'Felix', 'Monica'].map((name) {
return DropdownMenuItem<String>(
value: name,
// Your row here:
child: Row(
children: [
Icon(Icons.person),
Text(name),
],
),
);
}).toList(),
onChanged: (selectedName) {
setState(() {
dropdownValue = selectedName;
});
},
),
)
);
}
}
just set value for DropdownButton like code below:
String dropdownValue = 'Hillary';
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
appBar: AppBar(
title: Text('widget.title'),
),
body: Center(
child: DropdownButton<String>(
value: dropdownValue,
items: <String>['Hillary', 'Joe', 'Felix', 'Monica'].map((name) {
return DropdownMenuItem<String>(
value: name,
// Your row here:
child: Row(
children: [
Icon(Icons.person),
Text(name),
],
),
);
}).toList(),
onChanged: (selectedName) {
setState(() {
dropdownValue = selectedName;
});
},
),
));
}
for Change icon one way is using Map like code below:
String dropdownValue = 'Hillary';
Map<String, IconData> map = {
'Hillary': Icons.language,
'Joe': Icons.person,
'Felix': Icons.print,
'Monica': Icons.title
};
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return Scaffold(
appBar: AppBar(
title: Text('widget.title'),
),
body: Center(
child: DropdownButton<String>(
value: dropdownValue,
items: <String>['Hillary', 'Joe', 'Felix', 'Monica'].map((name) {
return DropdownMenuItem<String>(
value: name,
// Your row here:
child: Row(
children: [
Icon(map[name]),
Text(name),
],
),
);
}).toList(),
onChanged: (selectedName) {
setState(() {
dropdownValue = selectedName;
});
},
),
));
}

flutter drawer to remember the clicked item

I want to remember the item that was clicked in drawer .
I am using the same widget for drawer ( sameDrawerOnly ) in all three widgets ( MyHomePage , FirstPage and SecondPage) and using variable itemClicked to trackthe item that was tapped inside setState . But the conditional formatting is not working.
Here is the code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
DrawerOnly sameDrawerOnly = DrawerOnly();
class MyApp extends StatelessWidget {
final appTitle = 'Drawer Demo';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: Center(child: Text('My Page!')),
drawer: sameDrawerOnly,
);
}
}
class DrawerOnly extends StatefulWidget {
const DrawerOnly ({
Key key,
}) : super(key: key);
#override
_DrawerOnlyState createState() => _DrawerOnlyState();
}
class _DrawerOnlyState extends State<DrawerOnly > {
int itemClicked = 0;
#override
Widget build(BuildContext ctxt) {
return Drawer(
child: new ListView(
children: <Widget>[
new DrawerHeader(
child: new Text("DRAWER HEADER.."),
decoration: new BoxDecoration(
color: Colors.orange
),
),
new ListTile(
title: new Text("Item => A", style: itemClicked==1 ? TextStyle( fontWeight: FontWeight.bold, color: Colors.red.withOpacity(0.6) ) : null),
onTap: () {
Navigator.pop(ctxt);
setState(() {
itemClicked=1;
});
Navigator.push(ctxt,
new MaterialPageRoute(builder: (ctxt) => new FirstPage()));
},
),
new ListTile(
title: new Text("Item => 2", style: itemClicked==2 ? TextStyle( fontWeight: FontWeight.bold , color: Colors.green.withOpacity(0.6) ) : TextStyle()),
onTap: () {
Navigator.pop(ctxt);
setState(() {
itemClicked=2;
});
Navigator.push(ctxt,
new MaterialPageRoute(builder: (ctxt) => new SecondPage()));
},
),
],
)
);
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext ctxt) {
return new Scaffold(
drawer: sameDrawerOnly,
appBar: new AppBar(title: new Text("First Page"),),
body: new Text("I belongs to First Page"),
);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext ctxt) {
return new Scaffold(
drawer: sameDrawerOnly,
appBar: new AppBar(title: new Text("Second Page"),),
body: new Text("I belongs to Second Page"),
);
}
}
What went wrong
Although sameDrawerOnly was declared at the top most part of your file. Everytime the widget re-draws your app's screens, eg. opening FirstPage via MaterialPageRoute, the variable in the DrawerOnly widget will always stay to zero. Because it is always re-drawn based on your configuration.
What you can do
Hotfix: Make itemClicked a static variable. (Not Recommended)
// Before
int itemClicked
// After
static int itemClicked
Alternatively, you can refactor your code and use PageView instead of opening a new Scaffold widget every time you switch between drawer items. Then, you can now use currentPageValue to determine what item was selected by the user.
MyHomePage.dart
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final appTitle = 'Drawer Demo';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
#override
createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
PageController _pageController;
double currentPageValue = 0.0;
#override
void initState() {
super.initState();
_pageController = PageController();
_pageController.addListener(() {
setState(() {
currentPageValue = _pageController.page;
// Do whatever you like with the page value
});
});
}
#override
void dispose() {
_pageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: PageView(
controller: _pageController,
children: <Widget>[
FirstPage(),
SecondPage(),
],
),
),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Item 1'),
onTap: () {
_pageController.jumpToPage(0);
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
_pageController.jumpToPage(1);
Navigator.pop(context);
},
),
],
),
),
);
}
}
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(color: Colors.red);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(color: Colors.yellow);
}
}
View on dartpad.dev.
More on:
https://flutter.dev/docs/cookbook/design/drawer