Building a flutter app. I want one page to display in landscape, and the rest of the app to display in portrait. I can make that happen using techniques that I've found here and elsewhere, but it doesn't work very well. On initially entering the landscape screen, there's a kind of "shudder" while the app seems to be figuring out what to do. Then it displays ok. But on going back, the original screen first is displayed in landscape for a considerable time (nearly a second), and then there's another "shudder" before the screen is displayed in portrait. Simplified main.dart below. What am I doing wrong?
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class ScreenOne extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('screen one'),
),
body: Column(
children: <Widget>[
Center(
child: Text('some text'),
),
RaisedButton(
child: Text('Go to screen two'),
onPressed: () {
Navigator.pushNamed(
context,
'screenTwo',
);
},
)
],
),
);
}
}
class ScreenTwo extends StatefulWidget {
#override
_ScreenTwoState createState() => _ScreenTwoState();
}
class _ScreenTwoState extends State<ScreenTwo> {
#override
void dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
super.dispose();
}
#override
Widget build(BuildContext context) {
if (MediaQuery.of(context).orientation != null) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
]);
}
return Scaffold(
appBar: AppBar(
title: Text('screen two'),
),
body: Center(
child: Text('other text'),
),
);
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ScreenOne(),
routes: {
'screenTwo': (ctx) => ScreenTwo(),
},
);
}
}
Modify your second screen like this
return WillPopScope(
onWillPop: () {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
Navigator.of(context).pop();
//we need to return a future
return Future.value(false);
},
child: Scaffold(
appBar: AppBar(
title: Text('screen two'),
),
body: Center(
child: Text('other text'),
),
),
);
Related
I've followed some online tutorials and managed to implement ChangeNotifier when the app has a single route however none of these explain how to implement this when the app has more than one route (screen) which is rather the point!
I made an attempt to figure this out myself but when the app runs in the emulator I get a blank screen.
/* main.dart */
import 'dart:collection'; // used in test.dart
import 'package:flutter/foundation.dart'; // used in test.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Person extends ChangeNotifier {
Person({this.firstName});
String firstName = '';
void updateName(String n) {
this.firstName = n;
notifyListeners();
}
}
void main() {
runApp(
Provider(
create: (_) => Person(firstName: 'Mark'),
child: MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomeRoute(),
'/second': (context) => SecondRoute(),
'/third': (context) => ThirdRoute(),
},
),
)
);
}
class HomeRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(Provider.of<Person>(context).firstName),
),
body: Center(
child: new IconButton(
icon: new Icon(Icons.favorite, color: Colors.redAccent),
iconSize: 70.0,
onPressed: () {
Navigator.of(context).pushNamed("/second");
}
),
),
);
}
}
class SecondRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Second Page'),
),
body: Center(
child: Text(Provider.of<Person>(context).firstName),
),
);
}
}
class ThirdRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Third Page'),
),
body: Center(
child: Text('Third Route'),
),
);
}
}
The project builds and runs with no error messages which has stumped me.
Any thoughts?
Code developed in FlutLab
I wrote a code for ExitPopUp on a single page. Here is the code -
import 'package:flutter/material.dart';
class ExitPopUp extends StatelessWidget {
final page;
ExitPopUp(this.page);
#override
Widget build(BuildContext context) {
Future<bool> showExitPopUp() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Confirm"),
content: Text("Do you want to Exit ?"),
actions: <Widget>[
RaisedButton(child: Text("No"), onPressed: null),
RaisedButton(child: Text("Yes "), onPressed: null)
],
);
});
}
return WillPopScope(child: page, onWillPop: showExitPopUp);
}
}
Now I want to call this ExitPopUp from other page (***example:* registration.dart)**. Here is the code of Registration page-
import 'package:bloodhero/widgets/drawer.dart';
import 'package:bloodhero/widgets/exitpop.dart';
import 'package:flutter/material.dart';
import 'package:bloodhero/widgets/form.dart';
class Registration extends StatefulWidget {
#override
_RegistrationState createState() => _RegistrationState();
}
class _RegistrationState extends State<Registration> {
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
print("Hey I am Dialog Box");
return ExitPopUp();
},
child: Scaffold(
appBar: AppBar(
title: Text("Registration"),
backgroundColor: Colors.deepOrange,
),
drawer: DrawerApp(),
body: ListView(
children: <Widget>[
FormPage(),
],
)));
}
}
But It's not working. Error show in OnWillPop.
How can I fix it?
You can copy paste run full code below
You can pass Scaffold part code as parameter of ExitPopUp
code snippet
class _RegistrationState extends State<Registration> {
#override
Widget build(BuildContext context) {
return ExitPopUp(Scaffold(
appBar: AppBar(
title: Text("Registration"),
backgroundColor: Colors.deepOrange,
),
//drawer: DrawerApp(),
body: ListView(
children: <Widget>[
Text("FormPage()"),
],
)));
}
}
working demo
full code
import 'package:flutter/material.dart';
class ExitPopUp extends StatelessWidget {
final page;
ExitPopUp(this.page);
#override
Widget build(BuildContext context) {
Future<bool> showExitPopUp() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Confirm"),
content: Text("Do you want to Exit ?"),
actions: <Widget>[
RaisedButton(child: Text("No"), onPressed: (){}),
RaisedButton(child: Text("Yes "), onPressed: null)
],
);
});
}
return WillPopScope(child: page, onWillPop: showExitPopUp);
}
}
class Registration extends StatefulWidget {
#override
_RegistrationState createState() => _RegistrationState();
}
class _RegistrationState extends State<Registration> {
#override
Widget build(BuildContext context) {
return ExitPopUp(Scaffold(
appBar: AppBar(
title: Text("Registration"),
backgroundColor: Colors.deepOrange,
),
//drawer: DrawerApp(),
body: ListView(
children: <Widget>[
Text("FormPage()"),
],
)));
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Registration(),
);
}
}
I need a dynamic "back" button on every screen/page that also shows the title of the previous screen.
Navigation is done via global navigatorKey, pushing new routes is not done from a specific screen.
Is this possible with built-in navigator or it needs to be built from scratch?
Just pass the string you want to display to the constructor of the widget which will be your next page.
Example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
Widget build(context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: FlatButton(
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return Sec('title1');
}));
},
child: Text('Press here'))));
}
}
Widget backButton(context, t) {
return Row(children: [
Expanded(
child: IconButton(
icon: Icon(Icons.backspace),
onPressed: () => Navigator.pop(context),
),
),
Text(t,style:TextStyle(fontSize:16))
]);
}
class Sec extends StatelessWidget {
String t;
Sec(String x) {
t = x;
}
Widget build(context) {
return Scaffold(
appBar: AppBar(leading: backButton(context, t)),
body: Center(
child: FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Press here to go back'))));
}
}
Output
If I open my app, show a splash screen and then go to the main home page, my admob banner does not show, and the whole app freezes after a few seconds. But if I go directly from to the HomePage, bypassing the splash page, the banner shows no problem?
void main() {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
));
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]).then((_) {
Admob.initialize('ca-app-pub-3940256099942544~3347511713');
runApp(MyApp());
});
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
showPerformanceOverlay: false,
// home: SplashPage(),//ads do not show
home: HomePage(),//ads show no problem
);
}
}
class SplashPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: GestureDetector(
onTap: () {
Navigator.pushReplacement(// or with .push yields the same outcome
context,
MaterialPageRoute(
builder: (context) {
return HomePage();
},
settings: RouteSettings(isInitialRoute: true),
),
);
},
child: Container(
color: Colors.black,
child: Center(
child: Text('Splash page'),
),
),
),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Text('Home Page'),
bottomNavigationBar: Container(
height: 60,
child: Column(
children: <Widget>[
AdmobBanner(
adUnitId: 'ca-app-pub-3940256099942544/6300978111',
adSize: AdmobBannerSize.BANNER,
),
],
),
),
);
}
}
Any idea why this is happening? Something is not going from the SplashPage through to the HomePage to allow the banner to show.
I am trying to build a demo chat app with Flutter. After my main screen, I am using Navigator.push to go to the details screen.
Screenshot of problem:
build method of 1st screen:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Chat Thread App"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () {
Navigator.pushNamed(context, '/settings');
},
)
],
),
body: isLoading
? Center(
child: CircularProgressIndicator(),
)
: new ChatThreadListCard(messageThreads: _messageThreadLists, user: _user,),
);
}
code of Navigator.push method:
Navigator.push(context, MaterialPageRoute(
builder: (context) => ChatDetailsScreen(threadModel: new ThreadModel(
user.id,
user.fullName,
user.pic,
"otherId",
"otherName",
"otherPic",
post.threadId
)
),
),);
build method of 2nd screen, where the problem is produced:
return Scaffold(
appBar: AppBar(
title: Text("Chat demo"),
),
body: WillPopScope(
child: isLoading
? Center(
child: CircularProgressIndicator(),
)
: Stack(
alignment: AlignmentDirectional.bottomCenter,
children: <Widget>[
SizedBox(
width: 300,
height: 300,
),
Column(
children: <Widget>[
buildChat(),
buildInput(),
],
)
],
),
onWillPop: onBackPress,
),
);
the problem turns out to be, i was creating a MaterialApp widget in scaffold's body. so, when the onTap method was called, the new screen was replaced insdie the MaterialApp's area. didnt replace the whole screen.
the trick was to remove the return new MaterialApp().
thanks everyone.
I'm guessing something isn't working right with where you're setting up the Material App?
app.dart:
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage());
}
}
home_page and second_page
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
State createState() => HomePageState();
}
class HomePageState extends State<HomePage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Forward'), onPressed: () async {
await Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage()));
},)),
));
}
}
class SecondPage extends StatefulWidget {
#override
State createState() => SecondPageState();
}
class SecondPageState extends State<SecondPage> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Page'),
),
body: Container(
child: Center(child: RaisedButton(child: Text('Backward'), onPressed: () {
Navigator.of(context).pop();
},)),
));
}
}
Which produces: