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)'),
);
}
}
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 have done IconButton in my main.dart appBar and I want to Navigate using this Icon to my second page named OneDice. When im trying to push it by using
Navigator.of(context).push(MaterialPageRoute(builder: (_) => OneDice(),),);
it doesnt work and I have no idea why.... Can u help me plis? The problem is with (context). Error name is in the topic. And here is mine code. Thanks for all!
import 'package:dicee/OneDice.dart';
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
return runApp(
MaterialApp(
home: Scaffold(
backgroundColor: Colors.green.shade300,
body: const DicePage(),
appBar: AppBar(
title: const Center(child: Text('Dicee')),
backgroundColor: Colors.purple,
elevation: 10.0,
actions: [
IconButton(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (_) => OneDice(),),);
},
icon: const Icon(
Icons.indeterminate_check_box,
size: 40,
),
),
],
),
),
),
);
}
class DicePage extends StatefulWidget {
const DicePage({Key? key}) : super(key: key);
#override
State<DicePage> createState() => _DicePageState();
}
class _DicePageState extends State<DicePage> {
int leftDiceNumber = 1;
int rightDiceNumber = 3;
void rollDice() {
setState(() {
leftDiceNumber = Random().nextInt(6) + 1;
rightDiceNumber = Random().nextInt(6) + 1;
});
}
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Expanded(
child: TextButton(
onPressed: () {
// when i will press dice it calls Widget build to rebuild
rollDice();
},
child: Image.asset('images/dice$leftDiceNumber.png'),
),
),
Expanded(
child: TextButton(
onPressed: () {
rollDice();
},
child: Image.asset('images/dice$rightDiceNumber.png'),
),
),
],
),
);
}
}
You can only access context in the build method. You could do it like this.
void main() {
return runApp(
MaterialApp(
home:MyWidget(),
),
);
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.green.shade300,
body: const DicePage(),
appBar: AppBar(
title: const Center(child: Text('Dicee')),
backgroundColor: Colors.purple,
elevation: 10.0,
actions: [
IconButton(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (_) => OneDice(),),);
},
icon: const Icon(
Icons.indeterminate_check_box,
size: 40,
),
),
],
),
),
}
}
class DicePage extends StatefulWidget {
const DicePage({Key? key}) : super(key: key);
#override
State<DicePage> createState() => _DicePageState();
}
class _DicePageState extends State<DicePage> {
int leftDiceNumber = 1;
int rightDiceNumber = 3;
void rollDice() {
setState(() {
leftDiceNumber = Random().nextInt(6) + 1;
rightDiceNumber = Random().nextInt(6) + 1;
});
}
#override
Widget build(BuildContext context) {
return Center(
child: Row(
children: [
Expanded(
child: TextButton(
onPressed: () {
// when i will press dice it calls Widget build to rebuild
rollDice();
},
child: Image.asset('images/dice$leftDiceNumber.png'),
),
),
Expanded(
child: TextButton(
onPressed: () {
rollDice();
},
child: Image.asset('images/dice$rightDiceNumber.png'),
),
),
],
),
);
}
}
Just Use
Navigator.push(
context,
MaterialPageRoute(builder: (context) => OneDice()),);
And you can also use this code with GetX package
Get.to(() => OneDice());
I have created a simple app using InheritedWidget, just a counter app...
I have just four files:
main.dart.
CommonScreenProvider.dart.
first_screen.dart.
second_screen.dart.
the problem here when I am trying to use the counter function in in the second_screen and go back to the first_screen I can not find any updates till I use the counter but while I use counter in first screen I found the updated value in the second screen without problem, I think there's missing a refresh function or something?
Here's the code implementation...
CommonScreenProvider
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
first_screen
import 'package:flutter/material.dart';
import 'package:statemanagementtest/second_screen.dart';
import 'commom_screen_provider.dart';
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () {
Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
);
}),
),
);
}
}
second_screen
import 'package:flutter/material.dart';
import 'commom_screen_provider.dart';
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:statemanagementtest/commom_screen_provider.dart';
import 'package:statemanagementtest/first_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}
You can copy paste run full code below
Quick fix is move StatefulBuilder up and await Navigator.of(ctx).push then call setState
code snippet
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
working demo
full code
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
)),
);
});
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}
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;
main.dart
import 'dart:io';
import 'package:audioplayer/audioplayer.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:record_mp3/record_mp3.dart';
import 'package:permission_handler/permission_handler.dart';
import 'regitration.dart';
//import 'voiceCreate.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String statusText = "";
bool isComplete = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Scaffold(
drawer: Drawer(
elevation: 2.0,
child: ListView(
children: <Widget>[
ListTile(
title: Text('Home'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return MyApp();
},
),
);
},
),
ListTile(
title: Text('Sign up'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
},
),
ListTile(
title: Text('Sign in'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return LoginScreen();
},
),
);
// add sign in page
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
backgroundColor: Colors.grey.shade900,
appBar: AppBar(
title: Text('Myvo'),
centerTitle: true,
backgroundColor: Colors.tealAccent.shade700,
),
body: Column(children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 40,
onPressed: () async {
startRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.pause),
color: Colors.white,
iconSize: 40,
onPressed: () async {
pauseRecord();
}),
),
),
Expanded(
child: GestureDetector(
child: IconButton(
icon: Icon(Icons.stop),
color: Colors.white,
iconSize: 40,
onPressed: () async {
stopRecord();
}),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
statusText,
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
play();
},
child: Container(
margin: EdgeInsets.only(top: 30),
alignment: AlignmentDirectional.center,
width: 100,
height: 50,
child: isComplete && recordFilePath != null
? Text(
"play",
style: TextStyle(color: Colors.red, fontSize: 20),
)
: Container(),
),
),
]),
),
),
);
}
Future<bool> checkPermission() async {
if (!await Permission.microphone.isGranted) {
PermissionStatus status = await Permission.microphone.request();
if (status != PermissionStatus.granted) {
return false;
}
}
return true;
}
void startRecord() async {
bool hasPermission = await checkPermission();
if (hasPermission) {
statusText = "Recording...";
recordFilePath = await getFilePath();
isComplete = false;
RecordMp3.instance.start(recordFilePath, (type) {
statusText = "Record error--->$type";
setState(() {});
});
} else {
statusText = "No microphone permission";
}
setState(() {});
}
void pauseRecord() {
if (RecordMp3.instance.status == RecordStatus.PAUSE) {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
} else {
bool s = RecordMp3.instance.pause();
if (s) {
statusText = "Recording pause...";
setState(() {});
}
}
}
void stopRecord() {
bool s = RecordMp3.instance.stop();
if (s) {
statusText = "Record complete";
isComplete = true;
setState(() {});
}
}
void resumeRecord() {
bool s = RecordMp3.instance.resume();
if (s) {
statusText = "Recording...";
setState(() {});
}
}
String recordFilePath;
void play() {
if (recordFilePath != null && File(recordFilePath).existsSync()) {
AudioPlayer audioPlayer = AudioPlayer();
audioPlayer.play(recordFilePath, isLocal: true);
}
}
int i = 0;
Future<String> getFilePath() async {
Directory storageDirectory = await getApplicationDocumentsDirectory();
String sdPath = storageDirectory.path + "/record";
var d = Directory(sdPath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
return sdPath + "/test_${i++}.mp3";
}
}
I want to call the VoiceCreate function when clicking on onPressed
voiceCreate.dart
import 'package:flutter/material.dart';
import 'main.dart';
class VoiceCreate extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: () {}),
),
),
);
}
}
I want to call startRecord method from main.dart when clicking on onPressed
If you check the code of IconButton you'll see that onPressed is a VoidCallback, you can try to imitate the logic to do the same
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
And in main just call your widget VoiceCreate with an onPressed parameter
VoiceCreate(
onPressed: () => startRecord
)
edited code here. Still the startRecord() is not working. VoiceCreate() is working
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return VoiceCreate(onPressed: startRecord);
}),
);
},
// Add your onPressed code here!
child: Icon(Icons.add),
backgroundColor: Colors.tealAccent.shade700,
),
class VoiceCreate extends StatelessWidget {
final VoidCallback onPressed;
VoiceCreate({this.onPressed});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: Center(
child: IconButton(
icon: Icon(Icons.mic),
color: Colors.white,
iconSize: 70,
onPressed: onPressed),
),
),
);
}
}
You could do this by using shared view model across need widgets, like so:
I'd recommend to use this approach instead of callbacks and Stateful widgets
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Parent extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetBuilder<CommonViewModel>(
init: CommonViewModel(),
builder: (model) {
return Scaffold(
body: Column(
children: [
RaisedButton(onPressed: () => model.parentMethod(0)),
RaisedButton(onPressed: () => model.childMethod('call from parent')),
],
),
);
},
);
}
}
class Child extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetBuilder<CommonViewModel>(
builder: (model) {
return Scaffold(
body: Column(
children: [
RaisedButton(onPressed: () => model.childMethod('call from child')),
RaisedButton(onPressed: () => model.parentMethod(100)),
],
),
);
},
);
}
}
class CommonViewModel extends GetxController {
void parentMethod(int argument) {
print('Parent method $argument');
}
void childMethod(String argument) {
print('Child method $argument');
}
}