I'm trying to create a Material design app without the Scaffold element: Here is the purely default app:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Text(widget.title);
}
}
The result is:
How to fix that and use material styles without Scaffold?
Answer:
I need to use the Material widget. As a very beginner in Flutter I had read Material design tutorials and all of them were using the Scaffold widget. Thanks for pointing out the Material widget in comments.
It will not work without scaffold.
I think you are not getting what scaffold is and how it's behaviour is?
Scaffold is a widget which provides your screen/route a default behaviour similar to your android/ios screens like AppBar, Body, Title, FloatingActionButton, Drawer etc.
So that you do not have to make yourself a new structure.
If you are not using scaffold, then your page will act like a plain body structure in which you have to fill custom widgets as per your requirements.
For ex :
In android, Any Activity will have a default ActionBar. But, if you use NoActionBarActivity then Activity will be displayed without actionBar.
Even Scaffold works in the similar manner.
Updated Method :
#override
Widget build(BuildContext context) {
return Material(child: Center(child: Text(widget.title,)),color: Colors.white,);
}
You need to use Material Widget as a parent to behave the child widgets in the similar manner when using Scaffold.
Related
I've created a separate page with a StatefulWidget inside my Flutter app, and it has a Text widget inside of it.
However, when testing my app, the text does not render as intended - instead it shows up in a weird font with yellow underlining.
Here's my code:
import 'package:flutter/material.dart';
class ListsPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ListsPageState();
}
}
class _ListsPageState extends State {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Text('Log in page'),
);
}
}
Results image
Please remove Material Widget just return Text Widget Only, and please try to use the Stateless widget for better performance. Here's the example code
import 'package:flutter/material.dart';
import 'package:show_case/diementions/text_size.dart';
class TextWidget extends StatelessWidget {
const TextWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Text(
'Login Page',
style: kLabelStyle,
);
}
}
This is because of the app styling found in a widget higher in the tree. The text widget searches up the tree for the app default text style or one in another widget. If you wrap the Text widget in a Scaffold, that will include different styling.
See the her comment in the following code for where to try setting the default style:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return ProviderScope(
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData( //HERE
primarySwatch: Colors.blue,
),
home: const HomeScreen(),
),
);
}
}
Also try wrapping the Text widget like this:
DefaultTextStyle(
style: TextStyle(decoration: TextDecoration.none),
child: Text('Log in page'),
)
Set style in textwidget
Text("", style: TextStyle(decoration: TextDecoration.none),)
I am building a flutter app which simply views website URL. but I press back instead of navigating back it exists the app. I searched for solutions but no solution helped me. or that code doesn't support with latest flutter...
Here is my code
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return WebView(
initialUrl: 'https://flutter.dev',
);
}
}
This is happening because you are not coming from any page.
This is how currently your structure is following...
main() ===> MyApp() ===> MyHomePage(title: 'Flutter Demo Home Page') ===> "your-web-vide-page".
so if you would like to work back button then there has to be any page from the page you are going to like...
Navigator.push(context, MaterialPageRoute(builder: (context) {
return //<=== your-page-here
},));
You need to handle this manually.
Create a webView Controller first:
final Completer<WebViewController _controller =
Completer<WebViewController ();
and then create actions in the appBar, and add buttons to handle back and forward actions.
so on back button you would call:
controller.goBack();
and forward:
controller.goForward();
to handle the back button on android device you need to wrap your scaffold with willpopscop and then handle the case inside onWillPop function.
I am using bloc to manage my app state, I want to provide the bloc for all my app pages so I have inserted in the top of the widget tree so I can use it from any place in the widget tree, I have used it as the follows
1- main page
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return MyAppState();
}}
class MyAppState extends State<MyApp>{
#override
Widget build(BuildContext context) {
return BlocProvider<MyBloc>(
create: (BuildContext context) {
return MyBloc();
},
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: secondPage()),
);
}
}
2- secondPage:
class SecondPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return SecondPage State();
}
}
class SecondPage State extends State<SecondPage > {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('secondPage')),
body: BlocBuilder<CityBloc, CityState>(
builder: (BuildContext context, CityState state) {
.......
},));}}
but the flutter display an error that
BlocProvider.of() called with a context that does not contain a Bloc of type MyBloc
and this is a screenshot of the app's widgets tree
, what is the error, I want to provide mybloc for all widgets
note: the app run ok if I write the MainPage class and the secondPage class in the same page, but when I separate them the error appears
I was shocked by the solution, the problem was only in import, I have replaced
import '../blocs/blocs.dart';
With
import 'package: loony_trips / blocs / blocs.dart';
And everything was fixed, even though the two sentences were supposed to be the same
I have a page in my app that has some icons and animations on how to use the app.
I want to load this page on the first launch after installation and then I want any other launch of the app to go straight to the home page.
How can this be done?
I have seen a couple threads that confuse this question with splash screens, I only want this page to be launched once after installation and then never again.
Thank you
You must create splash screen and in this page check the shared preference that tell you if you already showed intro page or not
if you showed that page you can navigate to main page otherwise navigate to intro page
in intro page show whatever you want to show and in when introduction is over set the isIntroShowed or to true on shared preference
like below code
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SplashScreen(),
);
}
}
class SplashScreen extends StatefulWidget {
SplashScreen({Key key}) : super(key: key);
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
SharedPreferences.getInstance().then((prefs){
var isShowed =prefs.getBool("isIntroShowed");
if(isShowed!=null && isShowed)
{
//navigate to main page
}
else{
//navigate to intro page
}
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: CircularProgressIndicator(),),
);
}
}
class IntroPage extends StatelessWidget {
const IntroPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child:FlatButton(child: Text('intro done'),onPressed: ()async{
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setBool('isIntroShowed', true);
// navigate to main content
},)
),
);
}
}
I am working on a flutter app and I want to update the second level parent's state when a button is pressed. When the "PressMe" button is pressed, I want MyHomePage's state to have Widget2's title string saved in it's own state. Can someone please help me out with this? The button is a lower level widget and I want to pass the data up two levels. Thanks!
//main.dart
import 'package:flutter/material.dart';
import 'Widget1.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String title2;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Hello"),
),
body: Center(
child: Widget1(),
),
);
}
}
///////////////////////////////
//Widget1.dart
import 'package:flutter/material.dart';
import 'Widget2.dart';
class Widget1 extends StatefulWidget {
_Widget1State createState() => _Widget1State();
}
class _Widget1State extends State<Widget1> {
#override
Widget build(BuildContext context) {
return Widget2();
}
}
///////////////////////////////
//Widget2.dart
import 'package:flutter/material.dart';
class Widget2 extends StatefulWidget {
final String title = "Hello from Widget2";
_Widget2State createState() => _Widget2State();
}
class _Widget2State extends State<Widget2> {
String title = "Hello from Widget2";
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: null,
child: Text(
'PressMe',
style: TextStyle(fontSize: 20)
),
);
}
}
Thanks!
The easiest way to update your parent widget/class from a child is to pass down a function you create in the parent, then call that function from your child when you need to update it. However, that gets messy if you need to pass it down through multiple children. Usually in this case you'll want your parent to be a StatefulWidget and call setState inside the function you create when you assign the new title.
The next solution is to use InheritedWidgets or ChangeNotifiers.
The ideal solution would be to use some form of state management such as Provider or Bloc.