Flutter CupertinoTabBar BackNavigation from a Details Page - ios

I have a simple app with a CupertinoTabBar. It's almost like shown here: https://codesinsider.com/flutter-cupertino-tabbar/
child: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
label: "Home",
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.person),
label: "Profile",
)
],
),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
return data[index];
},
);
},
)
On a Details Page, which is accessible from "Home" and "Profile" there is a Back Button which should lead back to the previous Main page (Profile or Home) (In the Details Page the CupertinoTabBar is not shown) But I'm struggling to achieve this. Any tips would be helpful. (On Android it was easy with defining named routes in the BottomNavigationBar and then just call Navigator.pushNamed)
I need a way to go to page with index 0 or index 1 manually. The CupertinoTabBar should appear again when back is pressed.

Related

Page view controller attached to multiple scroll view

i have an issue with page view, it's working fine for first initialization (i mean when open the screen that contain page view from "Screen A" then go to open the "pageView screen" from other screen called "Screen B") in second time getting this issue
i think this issue happen because the controller re-intialiazed again, but i dispose the controller and make it equal to null when dispose screen
ScrollController attached to multiple scroll views.
'package:flutter/src/widgets/scroll_controller.dart':
package:flutter/…/widgets/scroll_controller.dart:1
Failed assertion: line 109 pos 12: '_positions.length == 1'
Using provider to handle change in tabBar and Page View, the below code of provider class
class PageViewProvider extends BaseViewModel {
// Tabs Controller
int selectedTapIndex = 0;
PageController? pageViewController;
initPageIndex(int index) {
if (pageViewController != null) {
pageViewController = null;
}
print('init index $index');
selectedTapIndex = index;
pageViewController = PageController(initialPage: index, keepPage: false);
}
void changeSelectedTapIndex(int index) {
selectedTapIndex = index;
setState(ViewState.Idle);
}
void changePageView(int index) {
pageViewController!.jumpToPage(index);
}
}
this the tabed item widget with onTap Function to change index of TabBar
Consumer<PageViewProvider>(
builder: (context, pageViewProvider, _) => Container(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: [
Icon(
iconData,
color:
pageViewProvider.selectedTapIndex == selectedIndex
? purpleColor
: grey500,
),
normal14Text(
title,
color:
pageViewProvider.selectedTapIndex == selectedIndex
? purpleColor
: grey500,
),
],
),
).onTap(() {
pageViewProvider.changeSelectedTapIndex(selectedIndex!);
pageViewProvider.changePageView(selectedIndex!);
}));
at least, this is the pageView body
Consumer<PageViewProvider>(
builder: (context, pageViewProvider, _) => PageView(
controller: pageViewProvider.pageViewController,
onPageChanged: (index) {
pageViewProvider.changeSelectedTapIndex(index);
},
pageSnapping: true,
children: [
LeadProfileContent(),
LeadProfileTimeLine(),
LeadProfileCases(),
LeadProfileDeals(),
],
),
),
Thanks in advance.
It's solved. The issue here was with the Consumer above the page view body. Just removed it, and then accessed the pageViewController like this:
context.read<PageViewProvider>.pageViewController

Why does flutter-test not render a Text widget in the following case?

I have a widget named GiftGrid that shows a placeholder Text widget when it receives no items, but the test that checks for the specific case fails, even though it works fine in the app:
testWidgets('Null list shows placeholder', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
localizationsDelegates: [MyLocalizationsDelegate()],
home: GiftGrid(null)));
var a = tester.allWidgets.toList();
expect(find.text("PROPER_QUADRUPLE_CHECKED_STRING"), findsOneWidget);
});
where GiftGrid is defined as follows:
return (widget.giftList?.isEmpty ?? true)
? Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(MyLocalizations.of(context).stringThatTranslatesToSameAsTest),
),
) : StaggeredGridBuilder(...);
The debugger shows the contents of a as follows (sorry for the screenshot, I couldn't find a better way to show it):
EDIT: GifGrid receives a List as the parameter and the following test passes:
testWidgets('Gift shows thumbnail if available', (WidgetTester tester) async {
var gift = GiftModel()
..images = [
"OTHER_IMG_LINK"
]
..thumbnail =
"IMG_LINK";
// Build our app and trigger a frame.
await tester.pumpWidget(MaterialApp(
home: GiftGrid([gift]),
));
expect(find.byWidgetPredicate((widget) {
return widget is TransitionToImage &&
(widget.image as AdvancedNetworkImage).url ==
"IMG_LINK";
}), findsOneWidget);
});

How to direct to initial page of Application after pressing the button, i.e. in 'OnPress' ? [Flutter]

I have a button, for which I want that when it is pressed, the home page of the app is opened. I have a Web View Plugin. My application is a Web View app, with url as 'www.google.com'.
Here is my code:
FlatButton(onPressed: (){ setState(() => WebviewScaffold(url: "http://www.google.com" ))}
To move between your classes you can use:
Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context) =>
new YouRItinitialPageCass()),);
}
But if you just want to go back you can use:
onPressed: () {Navigator.pop(context);},

How to preserve state of Widgets with BottomNavigationBar in Flutter? [duplicate]

This question already has answers here:
How to preserve widget states in flutter, when navigating using BottomNavigationBar?
(9 answers)
Closed 3 years ago.
I have a BottomNavigationBar, specifically a BubbleBottomBar. I have nested MaterialApps to give a new Navigator to the inner Widgets. However, when I switch tabs each widget in the bottom navigation bar is rebuilt. This is not good for me, as I want to keep the widgets in the same state. How would I achieve this?
I think you can easily solve that problem with using CupertinoTabScaffold&CuppertinoTabBar&CupertinoTabView it has that feature.
read more about there if you needed: Cupertino Widgets
official example : Cupertino Navigation&TabBar
this is my code it works the way you want it to work.(not rebuilding when you change tabs) you can convert it to yours:
import 'package:flutter/cupertino.dart';
CupertinoTabScaffold(
tabBar: CupertinoTabBar(items: [
BottomNavigationBarItem(
icon: Icon(Icons.explore), title: Text('Explore')),
BottomNavigationBarItem(
icon: Icon(Icons.card_travel), title: Text('Adventure')),
BottomNavigationBarItem(
icon: Icon(Icons.search), title: Text('Search')),
BottomNavigationBarItem(
icon: Icon(Icons.collections_bookmark),
title: Text('Bookmarks')),
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text('Profile')),
]),
tabBuilder: (context, index) {
return CupertinoTabView(
builder: (context) {
switch (index) {
case 0:
return ExplorePage();
break;
case 1:
return AdventurePage();
break;
case 2:
return SearchTourPage();
break;
case 3:
return Text('Bookmark Page');
break;
case 4:
return ProfilePage();
break;
default:
return SearchTourPage();
}
},
);
})
You can use AutomaticKeepAliveClientMixin to force your bottom bar content to not be disposed. But for this thing to work you might have to wrap your BottomNavigationBar inside a Stateful Widget.
I think this question might have the deatiled answer that you're looking for.
Example:
class CustomBottomBar extends StatefulWidget {
#override
_CustomBottomBarState createState() => _CustomBottomBarState();
}
class _CustomBottomBarState extends State<CustomBottomBar> with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
return BubbleBottomBar(
/*Your bottom bar code goes here*/
);
}
// Setting it true will force the bottom bar to never be disposed. This could be dangerous.
#override
bool get wantKeepAlive => true;
}

How to prevent changes in a dropdown in Flutter?

I tried to ask the user, if he is sure to change the data after pressing on a dropdown menu.
Currently, I launch an alert dialog after onChanged. Asking the user "Are you sure to change data ?". If Yes , I save the data changes. If "No", I close the alert dialog.
But if user chooses "No", the data has been changed and I don't want to change the data... How can I stop the change? I have a complicated solution where I save all data change, and when the user presses NO, I load the last data save before "NO" but I found this to complicated. Are there any other, more simple solution ? Thank you
Here is my code :
new DropdownButton<String>(
onChanged: (String changedValue) {
dialog(); //lanche dialog with choice of data modification
data=changedValue;
setState(() {
data;
});
},
value: data,
items: <String>['data1', 'data2', 'data3','data4', 'data5']
.map((String changedValue) {
return new DropdownMenuItem<String>(
value: changedValue,
child: new Text(changedValue),
);
}).toList()),
You should update the setState data value in your decision function. Check the following code.
new DropdownButton<String>(
onChanged: (String changedValue) {
_showDialog(changedValue); // I changed this.
},
value: data,
items: <String>['data1', 'data2', 'data3', 'data4', 'data5']
.map((String changedValue) {
return new DropdownMenuItem<String>(
value: changedValue,
child: new Text(changedValue),
);
}).toList()),
void _showDialog(selection) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Alert Dialog title"),
content: new Text("Alert Dialog body"),
actions: <Widget>[
new FlatButton(
child: new Text("No"),
onPressed: () {
Navigator.of(context).pop();
},
),
new FlatButton(
child: new Text("Yes"),
onPressed: () {
// this is where data value updates.
setState(() {
data = selection;
});
Navigator.of(context).pop();
},
),
],
);
},
);
}
I know this is too late to answer this question since this question was asked almost 4 years back from now. But some one like me will come around this question I guess. Here is the answer for you guys.
We can just reset the value of a dropdown to its initial value by calling reset method on the key of the dropdown button's state key.
Declare a global key for DropDownButton widget in the state class of your widget or screen
final _dropDownKey = GlobalKey<FormFieldState>();
Attach the key in the constructor of your dropdown button
You can now call reset method from the current state of the dropdown key to reset the dropdown value to its initial value.
_dropDownKey.currentState?.reset();
in my case when the user taps "NO" in the confirmation dialog, I have to set the old value in the dropdown.
What I have done is I waited for the result from alert dialog by async/await (alert dialog returns a nullable bool). When the pop up is closed a boolean or null will be returned. I added a if statement to reset the dropdown value if alert dialog returns false or null (which means user tapped on "NO" button or user dismissed the dialog by tapping on the empty area).
Future<void> _showDropDownChangeConfirmAlert(BuildContext context, FBO? fbo){
......
final isChangeConfirmed = await AlertDialogUtils.showConfirmationDialog(
context,
title: title,
content: content,
onPrimaryActionPressed: () => widget.onFboSelected.call(fbo),
);
// If the user taps on No in the confirmation dialog
// Below code resets the dropdown value to the old selected FBO
if ((isChangeConfirmed ?? false) == false) {
if (mounted) {
_dropDownKey.currentState?.reset();
}
}
....
}
Ps: AlertDialogUtils is a class in my project. It won't works in your project. Copy the idea not the code :)

Resources