How to navigate properly in SplitScreen - flutter

I am working on the iPad and I have set up the screen to be SplitScreens. Thus I have two Navigators side by side. However, when I push a new Screen from the second Navigator I get a weird animation where the second screen (right) overlaps the first screen (left).
Please look at this video that explains it very good:
https://imgur.com/a/93UmrGm
SplitView(
menu: Navigator(
key: firstSplitNavigatorKey,
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) =>
const KursplanungScreen(title: 'Demo App'),
);
},
),
content: Navigator(
key: secondSplitNavigatorKey,
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => const Scaffold(
body: Center(
child: Text(
"Herzlich Willkommen!"))),
);
},
),
menuWidth: 300,
),
Then somewhere in the second screen i call this:
TextButton(
onPressed: () => secondSplitNavigatorKey.currentState!.push(
MaterialPageRoute(
builder: (_) => const CourseOverviewScreen(),
),
),
child: const Text("Bearbeiten"),
),
How can I avoid that third weird animation?

You need to use a Navigator object to handle the right side pages.Use a Navigator object as widget father of the right side and handle the stack of pages to navigate only in this side. The default Navigator will change the entire page and will create a whole new one.
The left side, don't need to have a Navigator, only handle it using Widgets states(StatefullWidget or something like that).
SplitView(
menu: MenuSideBar(
onChangeSection: (Widget section) {
setState((){
pages.last=section;
});
}),
content: Navigator(
pages: pages,
),
),

Related

How to change state to previous state in bloc?

I have sigIn function that get data from Api and move to another screen if request is successful and if request is not successful then show alertDialog
I change state and before fetching data I show CircularProgressIndicator to make user know that data is fetching.
But when alertDialog window pops up and I close it then CircularProgressIndicator doesn't disappear. How to remove WaitingSignInAuth and show me Scaffold with inputs
When error comes then I emit ErrorSignInAuth but why there is WaitingSignInAuth to.. Why ErrorSignInAuth doesn't replace WaitingSignInAuth or it should work differently?
This is the code:
#override
Widget build(BuildContext context) {
return BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) {
if (state is WaitingSignInAuth) {
showDialog(
context: context,
builder: (context) => Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.black.withOpacity(0.6),
child: const Center(
child: CircularProgressIndicator(
strokeWidth: 1,
color: Colors.black,
backgroundColor: Colors.white,
),
),
));
}
if (state is ErrorSignInAuth) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Bad request"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text("Error")
],
),
),
actions: <Widget>[
TextButton(
child: const Text("Close"),
onPressed: () {
Navigator.pop(context); // If i press it then alertDialog diappears but not the loading circle
},
)
],
);
}
);
}
},
);
}
This is how it looks like:
The issue is, that you showDialog() twice. First is shown when WaitingSignInAuth state is fired, and the second one when you receive ErrorSignInAuth.
So Navigator.pop(context); in the "error" alert dialog closes only the showDialog that you've triggered in if (state is ErrorSignInAuth), the second dialog, which contains progress indicator is still visible.
To easy fix it, you can change your code to:
TextButton(
child: const Text("Close"),
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
},
)
But in my opinion thats not the best fix to your issue. IMO you don't need to show ProgressIndicator for WaitingSignInAuth in the dialog. Adjust your UI in the way, that the container with progress indicator will be displayed over it, but this doesn't need to be a dialog.

Flutter Modal Bottom Sheet with Navigator does not pop as expected

I a working with ModalBottomSheet and I love the package. However I am encountering an issue when trying to navigate with in a ModalBottomSheet.
Here is a ScreenVideo for a better understanding.
As you can see the View is presented as a ModalBottomSheet. But when popping it, it is not simply dismissing to the bottom but instead it is popping to some empty screen with a MaterialPage Pop animation.
I changed my code so I can push with a MaterialPageRoute-Animation inside that ModalBottomSheet. Before that everything was working as expected.
Here is my Page:
class _AboutScreenState extends State<AboutScreen> {
#override
Widget build(BuildContext context) {
return Material(
color: AppColors.primary,
child: Navigator(
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context2) => Builder(
builder: (context) => CupertinoPageScaffold(
backgroundColor: AppColors.secondary,
resizeToAvoidBottomInset: false,
child: SafeArea(
child: Padding(
padding: EdgeInsets.all(sidePadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButtonWithExpandedTouchTarget(
onTapped: () {
Navigator.pop(context);
},
svgPath: 'assets/icons/down.svg',
),
],
),
Text(
'About',
style: AppTextStyles.montserratH2SemiBold,
),
...
RoundedCornersTextButton(
title: 'Impressum',
onTap: () {
Navigator.pop(context);
},
textColor: AppColors.primary,
backgroundColor: AppColors.secondary,
borderColor: AppColors.primary,
),
],
),
),
)),
),
),
),
);
}
}
I was simply following this example. What am I missing here? With the code above I can push inside the ModalSheet as expected with a MaterialPageRoute Animation but popping the first screen brings up the issue...
Let me know if you need any more info! Any help is appreciated :)
I think you are popping with the wrong context. The example is popping with rootContext, which is from the top-most widget in the hierarchy. You are popping from with context, defined at your lowest builder in the hierarchy.
I believe you are using the incorrect context. rootContext, which is from the top-most widget in the hierarchy, is what makes the sample pop. You're popping from your lowest builder in the hierarchy, which is dictated by context.

What does MaterialPageRoute with the context?

What does MaterialPageRoute do with context?
And what is the purpose of builder: here.
MaterialPageRoute(builder: (context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
Every state of widget required some context to perform some work, direct or indirect context should be used.
The [BuildContext] for a particular widget can change location over time as the widget is moved around the tree. Because of this, values returned from
the methods in this class should not be cached beyond the execution of a
single synchronous function.
Example:
In the question code for back navigation used Navigator.pop(context); so it will be running in a separate state, not the build(contex) from where navigation starts

How to transition to a new screen instantly

I want to create a transition immediately from one screen to another (no animation). However isInitialRoute generates an error due to an update to the Router widget. The suggestion is to use onGenerateInitialRoutes but I am not sure how to implement it.
The flutter design doc recommends this:
Routes & RouteSettings
Currently, the only way to add a Route to the history stack without playing its entrance animation is to mark it as an initial route in its RouteSettings. The declarative API requires that routes can be added without animation at any time. This is useful when the route is covered by another route and playing the animation simply doesn't make sense. To support this, a didAdd method is added to the Route interface. This method is called by the Navigator instead of didPush when the Route should just be added without its regular entrance animation. To simplify things, this new method will also be used to bring the initial route on screen. This makes the RouteSettings.initialRoute parameter useless and it will be removed from RouteSettings. This is a minor breaking change.
This is the code that is generating the error on isInitialRoute:
import 'package:flutter/cupertino.dart'
show
CupertinoApp,
CupertinoButton,
CupertinoPageRoute,
CupertinoPageScaffold;
import 'package:flutter/widgets.dart'
show
BuildContext,
Center,
Column,
Navigator,
Route,
RouteSettings,
SafeArea,
Spacer,
Text,
runApp,
Widget;
Widget makeButton(BuildContext context, String routeName) =>
new CupertinoButton(
onPressed: () => Navigator.pushReplacementNamed(context, routeName),
child: Text('Go to \'$routeName\''),
);
Route generateRoute(RouteSettings settings) {
switch (settings.name) {
case 'not-animated':
return new CupertinoPageRoute(
settings: RouteSettings(name: settings.name, isInitialRoute: true),
builder: (context) => CupertinoPageScaffold(
child: SafeArea(
child: Center(
child: Column(
children: [
Spacer(),
Text('This is \'not-animated\''),
makeButton(context, 'animated'),
Spacer(),
],
),
),
),
),
);
default:
return null;
}
}
void main() {
runApp(
CupertinoApp(
onGenerateRoute: generateRoute,
initialRoute: 'animated',
routes: {
'animated': (context) => CupertinoPageScaffold(
child: SafeArea(
child: Center(
child: Column(
children: [
Spacer(),
Text('This is \'animated\''),
makeButton(context, 'not-animated'),
Spacer(),
],
),
),
),
),
},
),
);
}
If You Want to just navigate your screen add this to your code
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => yoursecondscreenname()),
);
},

back button inside AppBar showing black screen in flutter

I have bottom tab navigator that contains of A and B screens, inside B screen I have widget that navigate to C page and inside C page I want to add back arrow to go back to previous screen (B screen), so...
I have simple widget that the code looks like this
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
resizeToAvoidBottomPadding: false,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(),
),
title: Text("XXX"),
centerTitle: true,
),
body: detail()));
}
the problem is whenever I click back arrow.. it turns to black screen... I don't get any idea what the problem is... so is there a way to go to my previous screen?
and this is how I ndo navigate from B screen to C page
InkWell(
onTap: () {Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => new NextScreen(check: values)));
},
child: Text(
"Next...",
style: TextStyle(
fontSize: 13.0,
),
),
)
The reason why you see a blank screen is because you navigated using pushReplacement. What pushReplacement does it that it will navigate to the next screen without stacking itself to the route meaning that it will make the app forget that the last screen was your screen B. Try using Navigator.push() instead.
Here is an example:
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ScreenC()),
);
}