How can I implement the design in the image (sidebar and navigation menu) in Flutter using GetX? similarly to Tabs on the web.
This is a example, maybe it can help you:
import 'package:flutter/material.dart';
import '../../routes/app_pages.dart';
import 'package:get/get.dart';
class SideBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
DrawerHeader(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Icon(
Icons.person,
color: Colors.white,
size: 50.0,
),
),
Center(
child: Text(
"Vakup",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 25),
),
),
],
),
decoration: BoxDecoration(
color: Colors.blueAccent,
),
),
ListTile(
leading: Icon(Icons.read_more),
title: Text('Leer datos'),
onTap: () {
if (Get.currentRoute == Routes.HOME) {
Get.back();
} else {
Get.toNamed(Routes.HOME);
}
},
),
ListTile(
leading: Icon(Icons.pets),
title: Text('Registrar animal'),
onTap: () {
if (Get.currentRoute == Routes.NEWANIMAL) {
Get.back();
} else {
Get.toNamed(Routes.NEWANIMAL);
}
},
),
ListTile(
leading: Icon(Icons.list_alt),
title: Text('Lista movimientos'),
onTap: () {
if (Get.currentRoute == Routes.MOVEMENTS) {
Get.back();
} else {
//Get.to
Get.toNamed(Routes.MOVEMENTS);
}
},
),
ListTile(
leading: Icon(Icons.list),
title: Text('Lista animales'),
onTap: () {
if (Get.currentRoute == Routes.LISTOFANIMALS) {
Get.back();
} else {
Get.toNamed(Routes.LISTOFANIMALS);
}
},
),
ListTile(
leading: Icon(Icons.edit),
title: Text('Grabar datos'),
onTap: () {
if (Get.currentRoute == Routes.GRABADO) {
Get.back();
} else {
Get.toNamed(Routes.GRABADO);
}
},
),
ListTile(
leading: Icon(Icons.bluetooth),
title: Text('Conexion BT'),
onTap: () {
if (Get.currentRoute == Routes.CONEXIONBT) {
Get.back();
} else {
Get.toNamed(Routes.CONEXIONBT);
}
},
),
ListTile(
leading: Icon(Icons.picture_as_pdf),
title: Text('Exportar Datos'),
onTap: () {
if (Get.currentRoute == Routes.EXPORT) {
Get.back();
} else {
Get.toNamed(Routes.EXPORT);
}
},
),
ListTile(
leading: Icon(Icons.recent_actors_rounded),
title: Text('Acerca de'),
onTap: () {
if (Get.currentRoute == Routes.ACERCA) {
Get.back();
} else {
Get.toNamed(Routes.ACERCA);
}
},
),
],
),
);
}
}
And the home part is:
import 'package:vakuprfid/app/modules/widgets/side_bar.dart';//import widget
class HomeView extends GetView<HomeController> {
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: SideBar(),
body: ...
);
}
}
This is the result:
For the main content put all the different view into a list and put it into PageView. And create a custom navigator and put these two widget into a Row:
Controller:
class SettingsController extends GetxController {
final PageController pageController =
PageController(initialPage: 1, keepPage: true);
}
Sidebar:
class MySideNavigation extends StatefulWidget {
MySideNavigation({Key? key}) : super(key: key);
#override
State<MySideNavigation> createState() => _MySideNavigationState();
}
class _MySideNavigationState extends State<MySideNavigation> {
#override
Widget build(BuildContext context) {
final SettingsController c = Get.find();
return NavigationRail(
selectedIndex: c.selectedViewIndex.value,
onDestinationSelected: (value) async {
setState(() {
c.selectedViewIndex(value);
c.pageController.jumpToPage(
value,
// duration: Duration(milliseconds: 500), curve: Curves.decelerate
);
});
},
labelType: NavigationRailLabelType.selected,
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.map_outlined),
selectedIcon: Icon(Icons.map_rounded),
label: Text(
'نقشه ها',
style: TextStyle(fontSize: 14, fontFamily: 'Vazir'),
),
),
NavigationRailDestination(
icon: Icon(Icons.map_outlined),
selectedIcon: Icon(Icons.map_rounded),
label: Text(
'نقشه ها',
style: TextStyle(fontSize: 14, fontFamily: 'Vazir'),
),
),
NavigationRailDestination(
icon: Icon(Icons.person_outline),
selectedIcon: Icon(Icons.person),
label: Text(
'پروفایل',
style: TextStyle(fontSize: 14, fontFamily: 'Vazir'),
),
),
],
);
}
}
GotFatherView:
class GodFatherView extends StatelessWidget {
GodFatherView({Key? key}) : super(key: key);
final PageStorageBucket bucket = PageStorageBucket();
final SettingsController c = Get.find();
List<Widget> pages = [
const KeepAlivePage(Page1()),
KeepAlivePage(Page2()),
const KeepAlivePage(Page3()),
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
MySideNavigation(),
Expanded(
child: PageView(
controller: c.pageController,
children: pages,
),
)
],
));
}
}
tap on below link to open screenshot: I don't have enough reputation to post image :))))))
Screeshot
Give a special attention to the sidebar navigator in MySideNavigation class:
NavigationRail(
selectedIndex: c.selectedViewIndex.value,
onDestinationSelected: (value) async {
setState(() {
c.pageController.jumpToPage(value);
});
},
When user tap on each NavigationRailDestination ,onDestinationSelected function will be called with an index. The index are representing the index of the destination view. Example: When user on [Page1() -> index:0] tab on the second NavigationRailDestination the index inside of function is 1, so you can use the PageController to navigate into [Page2() -> index:1].
Attention, Attention, More Attention:
If you don't like to lose the state(I mean when u navigate to another view and back to previous view don't rebuild it again). Sometimes we need to keep the state of widget, we change something, write something into a text field and etc. If you don't wrap it with this widget all the data will be loosed(or you can save it through another way).
Wrap your widget with this Widget see the GodFather View I wrap all pages with KeepAlivePage, In this widget I extend State of the widget with 'AutomaticKeepAliveClientMixin' and override its value bool get wantKeepAlive => true; .
import 'package:flutter/material.dart';
class KeepAlivePage extends StatefulWidget {
const KeepAlivePage(this.child, {Key? key}) : super(key: key);
final child;
#override
State<KeepAlivePage> createState() => _KeepAlivePageState();
}
class _KeepAlivePageState extends State<KeepAlivePage>
with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
super.build(context);
return widget.child;
}
#override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
it's easy,just let your right conent use GetMaterialApp and the route change is render right concent, then left sidler is a component warp your menuslider,
last control you left slider menuchange index.
show my code
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(dessignWidth, dessignHeight),
builder: () => BarcodeKeyboardListener(
onBarcodeScanned: (String codeValue) {},
child: Material(
child: MaterialApp(
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [
Locale('zh', 'CH'),
Locale('en', 'US'),
],
home: Row(
children: [
Material(
child: SliderMenu(),
),
Expanded(
child: GetMaterialApp(
debugShowCheckedModeBanner: false,
enableLog: true,
navigatorKey: Get.key,
routingCallback: RouteChangeMiddleWare.observer,
logWriterCallback: Logger.write,
initialRoute: AppPages.INITIAL,
getPages: AppPages.routes,
unknownRoute: AppPages.unknownRoute,
builder: EasyLoading.init(),
onInit: () =>
{logger.v('Global.CONFIG', AppConfig)}))
],
)),
)));
}```
hope to help you;
Related
In the following code i can add and remove Tabs to the screen. For removing, i have defide a Button on the AppBar that after pressing it a DropdownMenu appears who let me select which Tab i want to remove and it removes the selected Item.
The problem that i have is that when i select a item DropdownMenu it does not show the selected item.
Thanks in advance for some help.
Follows the complete code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
String? selectedTab = tabs[0].text;
var tabName = "";
static List<Tab> tabs = [
const Tab(text: ""),
];
List<Widget> tabViewChildren = [
Container(
height: 400,
),
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 0,
length: tabs.length,
child: Scaffold(
appBar: AppBar(
actions: <Widget>[
ElevatedButton.icon(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Enter tab name"),
content: TextField(
onChanged: (String value) {
tabName = value;
},
),
actions: <Widget>[
ElevatedButton(
child: const Text("Add"),
onPressed: () {
setState(() {
tabs.add(Tab(text: tabName));
tabViewChildren.add(Container(height: 400));
});
Navigator.of(context).pop();
},
),
],
);
},
);
},
icon: const Icon(
Icons.add_box,
),
label: const Text('Add Tab'),
),
Opacity(
opacity: tabs.isNotEmpty ? 1 : 0.4,
child: ElevatedButton.icon(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Select tab to remove"),
content: tabs.isNotEmpty
? DropdownButton<String>(
items: tabs
.map((tab) => DropdownMenuItem<String>(
value: tab.text,
child: Text(tab.text ?? ""),
))
.toList(),
onChanged: (String? value) {
setState(() {
selectedTab = value;
});
},
value: selectedTab,
)
: Container(),
actions: <Widget>[
ElevatedButton(
child: const Text("Remove"),
onPressed: () {
setState(() {
int index = tabs.indexWhere((tab) => tab.text == selectedTab);
tabs.removeAt(index);
tabViewChildren.removeAt(index);
selectedTab = tabs.isNotEmpty ? tabs[0].text : null;
});
Navigator.of(context).pop();
},
),
],
);
},
);
},
icon: const Icon(Icons.remove),
label: const Text('Remove Tab'),
),
),
],
title: const Text("Tab in Flutter"),
bottom: TabBar(tabs: tabs),
),
body: TabBarView(children: tabViewChildren)));
}
}
The Problem:
Flutter works as a tree, each node has its own build context so showDialog is returning a build with a new build context, therefore in your code whenever you call setState in the dialog => you are calling the setState for the parent context (page), basically, you are updating the Screen widget not the dialog widget.
The Solution:
you have to use StatefulBuilder inside the Dialog widget so that it will have its own setState functionality. see the code below
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
String? selectedTab = tabs[0].text;
var tabName = "";
static List<Tab> tabs = [
const Tab(text: ""),
];
List<Widget> tabViewChildren = [
Container(
height: 400,
),
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: 0,
length: tabs.length,
child: Scaffold(
appBar: AppBar(
actions: <Widget>[
ElevatedButton.icon(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Enter tab name"),
content: TextField(
onChanged: (String value) {
tabName = value;
},
),
actions: <Widget>[
ElevatedButton(
child: const Text("Add"),
onPressed: () {
setState(() {
tabs.add(Tab(text: tabName));
tabViewChildren.add(Container(height: 400));
});
Navigator.of(context).pop();
},
),
],
);
},
);
},
icon: const Icon(
Icons.add_box,
),
label: const Text('Add Tab'),
),
Opacity(
opacity: tabs.isNotEmpty ? 1 : 0.4,
child: ElevatedButton.icon(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) => AlertDialog(
title: const Text("Select tab to remove"),
content: tabs.isNotEmpty
? DropdownButton<String>(
items: tabs
.map(
(tab) => DropdownMenuItem<String>(
value: tab.text,
child: Text(tab.text ?? ""),
))
.toList(),
onChanged: (String? value) {
selectedTab = value;
setState(() {});
},
value: selectedTab,
)
: Container(),
actions: <Widget>[
ElevatedButton(
child: const Text("Remove"),
onPressed: () {
setState(() {
int index = tabs.indexWhere(
(tab) => tab.text == selectedTab);
tabs.removeAt(index);
tabViewChildren.removeAt(index);
selectedTab =
tabs.isNotEmpty ? tabs[0].text : null;
});
Navigator.of(context).pop();
},
),
],
),
);
},
);
},
icon: const Icon(Icons.remove),
label: const Text('Remove Tab'),
),
),
],
title: const Text("Tab in Flutter"),
bottom: TabBar(tabs: tabs),
),
body: TabBarView(children: tabViewChildren)));
}
}
I am currently developing a cross platform app in which I wanted to use a Sidebar for navigation on desktop and tablet view, but a bottom navigation bar for mobile, as it isn't really handy to use a sidebar on mobile.
I have trouble with the navigation part, as for the sidebar I can just easily use the push() function. But with the bottomNavBar I have to use the onItemTapped function with indexes etc. Is there an easy way to use them together/switch between them?
This is my navigation for the Sidebar:
#override
Widget build(BuildContext context) {
return ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => page),
);
},
And this is how I tried to do the bottomNavBar navigation:
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
body: PageNavigationItem.items.elementAt(_selectedIndex),
);
} // build method
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
Yes it is possible and once check below example code.
Video of how it will works.
https://drive.google.com/file/d/1BxK6qevJOu4qYrmnoTXdIYtqLAVC87ya/view?usp=share_link
Here we are creating a model for Title and onTap
class DataModel {
final String labelName;
final Function onTap;
const DataModel({required this.labelName, required this.onTap});
}
Here we are creating a list of DataModel so will use in Title and onTap.
List<DataModel> dataList = [
DataModel(
labelName: "First",
onTap: () {
print("first");
}),
DataModel(
labelName: "Second",
onTap: () {
print("Second");
}),
DataModel(
labelName: "Third",
onTap: () {
print("Third");
}),
DataModel(
labelName: "Fourth",
onTap: () {
print("Fourth");
}),
];
Function for get device is mobile or tablet
getDevice() {
return MediaQuery.of(context).size.width <= 800 ? "Mobile" : "Tablet";
}
here is full code of that page.
class MyHomePage extends StatefulWidget {
const MyHomePage({
super.key,
});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo Home Page"),
),
drawer: getDevice() == "Tablet"
? Drawer(
child: ListView.builder(
itemCount: dataList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(dataList[index].labelName),
onTap: () {
dataList[index].onTap();
},
);
},
))
: null,
bottomNavigationBar: getDevice() == "Mobile"
? BottomNavigationBar(
onTap: (value) {
dataList[value].onTap();
},
// backgroundColor: Colors.black,
items: dataList.map((e) => BottomNavigationBarItem(backgroundColor: Colors.black, icon: Icon(Icons.add), label: e.labelName)).toList(),
// items: <BottomNavigationBarItem>[
// BottomNavigationBarItem(label: "Test", icon: Icon(Icons.add)),
// BottomNavigationBarItem(label: "Test1", icon: Icon(Icons.add)),
// BottomNavigationBarItem(label: "Test2", icon: Icon(Icons.add)),
// BottomNavigationBarItem(label: "Test3", icon: Icon(Icons.add)),
// ],
)
: null,
body: Center(
child: TextButton(
onPressed: () {
setState(() {
// isHide = !isHide;
});
},
child: Text("Hide")),
),
);
}
I Hope these things are solve your issue.
There is, to my knowledge, no way to solve your issue unless you "make your own bottom navigation bar".
I would however ask if you don't want to use a Drawer widget instead of a bottom navigation bar as it is a way to keep your app consistent across platforms, follows flutters guidelines for projects and permit you to use push. It is a "sidebar" in a sense.
I would do my own bottom navigation bar if I felt I needed it no matter what,something like this:
import 'package:flutter/material.dart';
class BottomNavigationBarWidget extends StatelessWidget {
final List<Widget> children;
final Widget body;
const BottomNavigationBarWidget({Key? key, required this.children, required this.body}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(child: body),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
)
],
);
}
}
with this in the main page
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter app'),
),
body: BottomNavigationBarWidget(
body: Center(
child: Text('Hello world!'),
),
children: [
Column(children:[Icon(Icons.percent), Text("Test")])
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
print('Zapp!');
},
backgroundColor: Colors.yellow[700],
child: Icon(
Icons.bolt,
color: Colors.black,
),
),
);
}
}
This is the result
But seriously, it is just easier and better to use a Drawer widget
I'm using the PopupMenuButton in flutter for a web based project and trying to change the popupmenubutton icon when it's clicked. So in its initial state it would show Icons.menu and when opened, it could would Icons.close and once clicked again revert back to Icons.menu.
I have tried onSelected which does not get called at all when clicked in an attempt to change the icon.
I have used an icon or a child IconButton per the docs and used onPressed to setState however that doesn't work either.
Currently the elevated button when clicked, does not show the dropdown menu, nor does it update the icon.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool menuClicked = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
PointerInterceptor(
intercepting: true,
child: PopupMenuButton<String>(
offset: const Offset(10.0, 50.0),
color: Colors.black,
child: ElevatedButton(
onPressed: () {
setState(() {
menuClicked = !menuClicked;
});
},
child: Icon((menuClicked = true)
? Icons.menu
: Icons.close),),
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
PopupMenuItem(
value: "close",
child: ListTile(
leading: Icon(Icons.close, color: Colors.white),
title: Text('Close',
style: TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
}),
),
],
),
],
),
),
body: Center(
child: Text('test'),
),
);
}
}
Equal sign will be ==
Icon((menuClicked == true) ? Icons.menu : Icons.close),
or you can do
Icon(menuClicked ? Icons.menu : Icons.close),
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool menuClicked = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
GestureDetector(
behavior: HitTestBehavior.translucent,
onPanDown: (details) {
setState(() {
menuClicked = true;
});
},
child: PopupMenuButton<String>(
offset: const Offset(10.0, 50.0),
color: Colors.black,
onSelected: (value) {
setState(() {
menuClicked = false;
});
},
padding: EdgeInsets.zero,
onCanceled: () {
setState(() {
menuClicked = false;
});
},
child: Icon(menuClicked ? Icons.close : Icons.menu),
itemBuilder: (BuildContext context) => [
PopupMenuItem(
value: "close",
child: ListTile(
leading: Icon(Icons.close, color: Colors.white),
title: Text(
'Close',
style: TextStyle(color: Colors.white),
),
onTap: () {
Navigator.pop(context);
},
),
),
],
),
),
],
),
);
}
}
I would like to call function between another clas. So when the menu tapped from grabDrawer it will change the currentIndex at Main() class. Do you know how to do that? Here is so far I have tried.
main.dart
class _MainState extends State<Main> {
int currentIndex = 0;
Map<String,dynamic> searchParameter = {};
List screens = [
Home(),
Search({}),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
actions: [
Builder(builder: (context){
return IconButton(
onPressed: (){
Scaffold.of(context).openEndDrawer();
},
icon: const Icon(Icons.menu),
);
}),
],
),
endDrawer: const Drawer(
child:DrawerObject(),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.arrow_upward),
onPressed: () async{
await Future.delayed(Duration(milliseconds: 100),(){
globals.scrollController.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
});
},
),
body: screens[currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
onTap: (index) => setState(() {
if (index == 1) {
getSearchForm(context);
} else {
currentIndex = index;
searchParameter = {};
}
}),
selectedItemColor: Colors.white,
unselectedItemColor: Colors.grey[100],
type: BottomNavigationBarType.shifting,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.blue[500],
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Pencarian',
backgroundColor: Colors.orange[500],
),
],
),
);
}
//main function ===> NEED TO CALL THIS FUNCTION INSIDE grabDrawer.dart
Future UpdateIndex({int Index = 0}) async{
setState(() {
currentIndex = Index;
});
}
Future getSearchForm(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SearchForm(parameter:searchParameter)),
);
setState(() {
if (result != null) {
currentIndex = 1;
if(result!=searchParameter){
searchParameter = result;
screens[1] = CallLoading(show: ''); //set default to load
//set to new parameter (rebuilding widget)
Future.delayed(Duration(milliseconds: 500),(){
setState(() {
screens[1] = Search(searchParameter);
});
});
}
}
else{
}
});
}
}
Under this file, I need to call function from Main.UpdateIndex.
grabDrawer.dart
class DrawerObject extends StatelessWidget {
const DrawerObject({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.home),
title: Text('Cari Properti?'),
onTap: (){
===> CALL IT HERE
}
),
],
),
);
}
}
I really appreciate any answers. Thank you.
Change your grabDrawer.dart like this
class DrawerObject extends StatelessWidget {
void Function()? UpdateIndex;
DrawerObject({
this.UpdateIndex,
});
#override
Widget build(BuildContext context) {
return Container(
child: ListView(
children: [
ListTile(
leading: Icon(Icons.home),
title: Text('Cari Properti?'),
onTap: (){
UpdateIndex!();
}
),
],
),
);
}
}
And in your main.dart, call Drawer class like this
endDrawer: const Drawer(
child:DrawerObject(
UpdateIndex: UpdateIndex,
);
),
Hope this works for you.
Here is the clear way to pass data between one class to another class
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),
),
],
),
),
);
}
}
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)'),
);
}
}
I want to keep the bottomnavigationbar AppBar when navigating to a new screen. with save state when i back to page.
The trick is to use "IndexedStack" in the body, IndexedStack workers like Stack Widget :
IndexedStack(
index: _selectedIndex,
children: _widgetOptions,
)
pass list of widgets in 'children' & index of the widget in 'index'.
Here is the example code:
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: BottomNavPage(),
);
}
}
class BottomNavPage extends StatefulWidget {
const BottomNavPage({Key? key}) : super(key: key);
#override
_BottomNavPageState createState() => _BottomNavPageState();
}
class _BottomNavPageState extends State<BottomNavPage> {
int _selectedIndex = 0;
static const List<Widget> _widgetOptions = <Widget>[
NavHome(),
Text('Index 1: Business'),
Text('Index 2: School'),
Text('Index 3: Settings'),
];
Widget navHome() {
return Text(
'Index 0: Home',
);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('BottomNavigationBar Sample')),
body: IndexedStack(
index: _selectedIndex,
children: _widgetOptions,
),
bottomNavigationBar: Material(
child: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.blue,
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Home',
backgroundColor: Colors.blue,
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'Home',
backgroundColor: Colors.blue,
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Home',
backgroundColor: Colors.blue,
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.orange[400],
onTap: _onItemTapped,
),
),
);
}
}
class NavHome extends StatefulWidget {
const NavHome({
Key? key,
}) : super(key: key);
#override
_NavHomeState createState() => _NavHomeState();
}
class _NavHomeState extends State<NavHome> {
double _counter = 0;
void incrementCounter() {
setState(() {
_counter++;
});
}
void decrementCounter() {
setState(() {
_counter--;
});
}
#override
Widget build(BuildContext context) {
// Return a widget number in the center of the screen and button to increment the number
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Counter',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: Text('Increment'),
onPressed: incrementCounter,
),
SizedBox(width: 10),
ElevatedButton(
child: Text('Decrement'),
onPressed: decrementCounter,
),
],
),
],
),
);
}
}