I have two screen A and B, screen A has a bottom navigation bar.
After i pushed screen A to screen B, bottom navigation bar of screen A still pin on screen B.
I want show full screen B without bottom navigation of screen A.
This is a screen A, it has a bottom naviagtion bar:
class Parent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'TechOne',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: MyParentPage(title: 'TechOne'),
);
}
}
/*StatefulWidget is Widget with mutable*/
class MyParentPage extends StatefulWidget {
MyParentPage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyParentPageState createState() => _MyParentPageState();
}
/*State is a manager of StatefulWidget*/
class _MyParentPageState extends State<MyParentPage>
with SingleTickerProviderStateMixin {
var _itemSelected = 0;
TabController _tabController;
final _bodyUI = [
HomeUI(),
SearchUI(),
Center(
child: Text('Notification'),
),
Center(
child: Text('Account'),
),
];
_onBottomNavigationBarTap(int index) {
print(_itemSelected);
setState(() {
_itemSelected = index;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
_tabController = TabController(length: 4, vsync: this);
}
#override
Widget build(BuildContext context) {
_tabController.animateTo(_itemSelected);
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: Values.itemsBottomNavigationBar,
onTap: (index) {
_onBottomNavigationBarTap(index);
},
currentIndex: _itemSelected,
selectedItemColor: Colors.red,
backgroundColor: Colors.white,
type: BottomNavigationBarType.fixed,
),
body: TabBarView(
physics: NeverScrollableScrollPhysics(),
controller: _tabController,
children: <Widget>[
_bodyUI[0],
_bodyUI[0],
_bodyUI[2],
_bodyUI[3],
]));
}
}
Inside _bodyUI[0] widget, I push to screen B:
Navigator.push(context, MaterialPageRoute(builder: (context) => SearchUI()));
This is a screen B, bottom navigation bar still pin on here, i want hidden it:
class SearchUI extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: 'Search',
theme: ThemeData(primarySwatch: Colors.red),
home: MySearchPage(),
);
}
}
class MySearchPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _MySearchState();
}
}
class _MySearchState extends State<MySearchPage> {
final TextEditingController _textEditingController = TextEditingController();
final FocusNode _focusNode = FocusNode();
TextField _appBarTitle;
#override
void initState() {
// TODO: implement initState
super.initState();
_appBarTitle = TextField(
controller: _textEditingController,
focusNode: _focusNode,
autofocus: true,
textInputAction: TextInputAction.done,
textCapitalization: TextCapitalization.sentences,
cursorColor: Colors.white,
cursorRadius: Radius.circular(16),
maxLines: 1,
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
border: InputBorder.none,
prefixIcon: Icon(
Icons.search,
color: Colors.white,
),
suffixIcon: IconButton(icon: Icon(Icons.clear, color: Colors.white,), onPressed: (){
_textEditingController.clear();
}),
hintText: 'Search...',
hintStyle:
TextStyle(color: Colors.white.withOpacity(0.5), fontSize: 18)));
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: _appBarTitle,
),
body: Center(
child: Text('Search Screen'),
),
);
}
}
Your code is calling a SearchUI() class as one of the TabBarViews :
final _bodyUI = [
HomeUI(),
SearchUI(),
Center(
child: Text('Notification'),
),
Center(
child: Text('Account'),
),
];
Which means it's going to only change the view and keep the bar there.
EDIT : in a comment I deleted earlier I mentioned the nested MaterialApps may cause an issue. That seems to help correct the problem but in the comments below you now mention the addition of a back arrow. The quote below is taken from the Flutter documentation for AppBar.
If the leading widget is omitted, but the AppBar is in a Scaffold with
a Drawer, then a button will be inserted to open the drawer.
Otherwise, if the nearest Navigator has any previous routes, a
BackButton is inserted instead. This behavior can be turned off by
setting the automaticallyImplyLeading to false. In that case a null
leading widget will result in the middle/title widget stretching to
start.
Basically, that is something you can turn off using the property mentioned above.
Related
I am creating TabBar using Getx but getting the error Duplicate GlobalKey detected in the widget tree. So whenever I am going to the second Tab app doesn't show any content. How I solve the issue whenever I am using stateful widget it works but whenever trying Getx to create the TabBar using the stateless widget.
TabBar Class:
class Page2 extends StatelessWidget {
const Page2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final GetxTab getxTab = Get.put(GetxTab());
return MaterialApp(
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: getxTab.tabController,
tabs: getxTab.appTabs,
),
),
body: TabBarView(controller: getxTab.tabController, children: [
PageTabs1(),
GetxExample(),
])),
);
}
}
class GetxTab extends GetxController with SingleGetTickerProviderMixin {
late TabController tabController;
final List<Tab> appTabs = <Tab>[
Tab(
icon: Icon(
Icons.share,
),
text: ("Bottom Sheet")),
Tab(
icon: Icon(
Icons.share,
),
text: ("Getx")),
];
#override
void onInit() {
// TODO: implement onInit
super.onInit();
tabController = TabController(length: appTabs.length, vsync: this);
}
#override
void onClose() {
// TODO: implement onClose
super.onClose();
tabController.dispose();
}
}
First Page:
Updated: Problem solved I just figure out I make a mistake adding GetMaterialApp, Scaffold
both of my Parent and child class. Which conflicts one with another.
So I just remove the child GetMaterialApp( home: Scaffold(
class PageNav3 extends StatelessWidget {
const PageNav3({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Text(
"Nav1",
style: TextStyle(color: Colors.red),
),
),
);
}
}
Second Page:
This page causes the Issue
class GetxExample extends StatelessWidget {
GetxExample({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
bool value = true;
return GetMaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: GestureDetector(
child: Container(
width: double.infinity,
height: 45,
child: My_Button(
ButtonText: "Change",
Backcolors: Colors.black,
FontColors: Colors.white,
padBot: 5,
padTop: 5,
padRight: 5,
padLeft: 5),
),
onTap: () {
value = !value;
Get.bottomSheet(
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
color: Colors.blueGrey,
),
child: Wrap(
children: [
AddListTittle(
Tittle: "Camera",
des: "Add Photo by clicking Camera",
iconss: Icons.camera,
Index: 0,
reqIndex: ImageSource.camera,
),
AddListTittle(
Tittle: "Gallery",
des: "Add Photo from Gallery",
iconss: Icons.storage,
Index: 1,
reqIndex: ImageSource.gallery,
),
],
),
),
);
},
),
),
),
);
}
}
If you are using the scaffold keys to display snackbar, remove them and use the overlay support package, it offers a simpler implementation
Assumption and what I want to achieve
I want to make it so that after inputting into the TextField of the TodoAddPage class, it will be displayed in the TodoListPage class like a "TODO list".
Problems and error messages that are occurring
It looks like the following image.
! image description
The corresponding source code.
import 'package:flutter/material.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// app name
title: 'My Todo App',
theme: ThemeData(
// theme color
primarySwatch: Colors.blue,
),
// display the list list screen
home: TodoListPage(),
);
}
}
// Widget for list list screen
class MyTodoApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Todo App',
// App name
theme: ThemeData(
// theme color
primarySwatch: Colors.blue,
),
// Display the list list screen
home:
TodoListPage()
);
}
}
// Widget for list list screen
class TodoListPage extends StatefulWidget {
#override
_TodoListPageState createState() => _TodoListPageState();
}
class _TodoListPageState extends State<TodoListPage> {
// Todo list data
List<String> todoList = [];
#override
Widget build(BuildContext context) {
double _width = MediaQuery.of(context).size.width;
double _height = MediaQuery.of(context).size.height;
return Scaffold(
// Display the AppBar and set the title
appBar: AppBar(
title: Text('List of Lists'),
),
body: Container(
height: _height,
width: _width,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
const Color(0xffe4a972).withOpacity(0.6),
const Color(0xff9941d8).withOpacity(0.6), const Color(0xff9941d8).withOpacity(0.6),
],
begin: Alignment.topRight,
end: Alignment.bottomLeft,
),
),
child: ListView.builder(
itemCount: todoList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(todoList[index]),
),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
// "push" to transition to new screen
// receive the value passed from the add list screen
final newListText = await Navigator.of(context).push(
MaterialPageRoute(builder: (context) {
// specify the list add screen as the destination screen
return TodoAddPage();
}),
);
if (newListText ! = null) () {
// note that newListText will be null if we cancel it
setState(() {
// add list
todoList.add(newListText);
});
};
},
child: Icon(Icons.add),
),
// Create a ListView based on the data
);
}
}
// Widget for list add screen
class TodoAddPage extends StatefulWidget {
#override
_TodoAddPageState createState() => _TodoAddPageState();
}
class _TodoAddPageState extends State<TodoAddPage> {
// Have the input text as data
String _text = '';
// Widget to display based on the data
#override
Widget build(BuildContext context) {
return
Scaffold(
appBar: AppBar(
title: Text('Add list'),
),
body: Container(
// Add margins
padding: EdgeInsets.all(64),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Display the input text
Text(_text, style: TextStyle(color: Colors.blue)),
const SizedBox(height: 8),
// Input text
TextField(
// receive the value of the input text (value is the input text)
onChanged: (String value) {
// notify that the data has changed (refresh the screen)
setState(() {
// change the data
_text = value;
});
},
),
const SizedBox(height: 8),
Container(
// expand to full width
width: double.infinity,
// add list button
child: ElevatedButton(
onPressed: () {
// "pop" to go back to the previous screen
// pass the data from the "pop" argument to the previous screen
Navigator.of(context).pop(_text);
},
child: Text('add list', style: TextStyle(color: Colors.white)),
),
),
const SizedBox(height: 8),
Container(
// expand to full width
width: double.infinity,
// cancel button
child: TextButton(
// what to do when the button is clicked
onPressed: () {
// "pop" to go back to the previous screen
Navigator.of(context).pop();
},
child: Text('cancel'),
),
),
],
),
)
);
}
}
```
### Things I've tried
I've enclosed the Widget in a SingleChildScrollView.
However, when I press the button, it goes blank.
Is it possible for me to open a page with icons when I click on the place I drew in red in the picture, like the bottomnavbar on Instagram, but I want mine to be like in the picture
What you have to do is:
add a drawer to your scaffold
add a GlobalKey to your Widget which you will use to open the Drawer
Remove the AppBar Menu button if you don't want it there
Add a the button and Position it in your body
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 StatelessWidget {
final String title;
//Add GlobalKey which you will use to open the drawer
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
MyHomePage({Key? key, required this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
//Set GlobalKey
key: _scaffoldKey,
appBar: AppBar(title: Text(title),
//This will remove the AppBar menu button
automaticallyImplyLeading: false,),
body:
Center(child:
Container(
width: double.infinity,
alignment: Alignment.centerLeft,
child: InkWell(
//This function will open the Side Menu
onTap: ()=> _scaffoldKey.currentState?.openDrawer()
,
child: Icon(
Icons.menu,
size: 20,
),
),
),
),
//Add Drawer to your Scaffold
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: Text('Item 1'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
);
}
}
I am writing a flutter program where the user should select a value from a DropdownButtonFormField. once the selection is made, the choice should be displayed on the dropdown. I use a push route to get the data from a second screen in which the choice is utilized. My problem is after selecting the option, the page refreshes and therefore doesnt show the selected value on the dropdown.
Below is my code:
I create the Dropdownbuttonformfield in a file called shared.dart so I can call it in multiple files:
class UserDropdownList extends StatefulWidget {
#override
_UserDropdownListState createState() => _UserDropdownListState();
}
class _UserDropdownListState extends State<UserDropdownList> {
String currentUser;
#override
Widget build(BuildContext context) {
final user = Provider.of<List<User>>(context) ?? [];
return DropdownButtonFormField(
isExpanded: true,
decoration: textInputDecoration,
value: currentUser,
hint: Text(
'Incoming Officer',
),
onChanged: (val) {
setState(() => currentUser = val);
var route = MaterialPageRoute(
builder: (BuildContext context) =>
FinalForm(chosenUser: currentUser,)
);
Navigator.of(context).push(route);
},
// onChanged: (val) => setState(() => currentUser = val),
items: user.map((user){
return DropdownMenuItem(
value: user.userId,
child: Text(user.name)
);
}).toList(),
);
}
}
I then call the Custom button in my main page like so
class FinalForm extends StatefulWidget {
//code for importing selected user
final String chosenUser;
FinalForm({Key key, this.chosenUser}) : super (key: key);
#override
_FinalForm createState() => _FinalFormState();
}
class _FinalFormState extends State<FinalForm> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Final Form')
),
body: Form(
child: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
children: <Widget>[
SizedBox(height: 20.0),
Align(
child: Text(
'Select Incoming Officer',
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.blueAccent,
),
)
),
SizedBox(height: 20.0),
StreamProvider<List<User>>.value(
value: DatabaseService().users,
child: UserDropdownList(),
),
SizedBox(height: 20.0),
Text("${widget.chosenUser}"),
],),
),
),
);
}
}
Is there a way to keep the selected value on the dropdown or prevent the screen from reloading?
If you are navigating away from the current page / view, it would make sense for the current dropdown selection to be lost. You can pass the current selection as an argument to the push function to redisplay on the new page. Hth
I have a Native Android Fragment and I need to use inside a flutter project.
Inside a Android Project when you need to use a fragment something like
supportFragmentManager.beginTransaction()
.replace(R.id.content_fragment, it1,
"name")
.commit()
I would like to embed this fragment along with a BottonNavigationBar (second option for example).
I tried to follow some tutorials as:
https://medium.com/flutter-community/flutter-platformview-how-to-create-flutter-widgets-from-native-views-366e378115b6
https://60devs.com/how-to-add-native-code-to-flutter-app-using-platform-views-android.html
But I wasn`t able to adapt these tutorials for fragment or even activities becase they talk about Views.
Does anyone have any suggestions?
Obs: Just to clarify, I need to use a native screen inside a flutter screen.
But you can use flutter BottomNavigationBar
here is a demo of BottomNavigationBar
and it looks same as Bottomnavigation with fragment in android
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int index = 0;
void currentindex(value) {
setState(() {
this.index = value;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Icon(
MdiIcons.flower,
color: Colors.white,
),
title: Text(
widget.title,
style: TextStyle(color: Colors.white),
),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(MdiIcons.home),
title: Text("Home"),
),
BottomNavigationBarItem(
icon: Icon(MdiIcons.human),
title: Text("User"),
),
BottomNavigationBarItem(
icon: Icon(MdiIcons.imageAlbum),
title: Text("Theme"),
),
],
onTap: (index) => currentindex(index),
elevation: 19.0,
currentIndex: index,
),
body: Navtabwidget()[this.index],
);
}
List<Widget> Navtabwidget() {
return [
Homewidget(),
Userlistwidget(),
Settingwidget(),
];
}
}
i hope it helps
I used this, in a similar problem:
class DetailsScreen extends StatefulWidget {
#override
DetailsScreenState createState() {
return DetailsScreenState();
}
}
class DetailsScreenState extends State<DetailsScreen>
with SingleTickerProviderStateMixin {
TabController tabController;
#override
void initState() {
tabController = new TabController(length: 4, vsync: this);
super.initState();
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(67.0),
child: AppBar(
elevation: 10.0,
automaticallyImplyLeading: false,
flexibleSpace: Padding(
padding: const EdgeInsets.only(top: 0.0),
child: SafeArea(
child: getTabBar(),
),
),
),
),
body: getTabBarPages());
}
Widget getTabBar() {
return TabBar(controller: tabController, tabs: [
Tab(
text: AppLocalizations.of(context).translate("nav_dieta"),
icon: Icon(MdiIcons.silverwareForkKnife)),
Tab(
text: AppLocalizations.of(context).translate("nav_exercise"),
icon: Icon(MdiIcons.dumbbell)),
Tab(
text: AppLocalizations.of(context).translate("_news"),
icon: Icon(MdiIcons.newspaper)),
Tab(
text: AppLocalizations.of(context).translate("nav_info"),
icon: Icon(MdiIcons.accountDetails)),
]);
}
Widget getTabBarPages() {
return TabBarView(
controller: tabController,
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
MealPlanScreen(),
ExerciseScreen(),
Container(color: Colors.blue),
Container(color: Colors.yellow)
]);
}
}
Where MealPlanScreen and ExerciseScreen are StatefulWidget and those two Containers will be replaced with other classes that contain StatefulWidget.