I am trying to build a macOS desktop app with flutter. I want the app to be full-width, edge-to-edge. However, when I run the app via the simulator, or after the build, it always launches the app with size 800x600.
I have set the height and width of the root container to double.infinity. In fact, even if I set the height and width to 10.0, it always launches the app with 800x600. I am new to flutter, so probably missing some fundamentals. Most tutorials I have come across talk about building a mobile app where this is never a problem because the app always launches to its full width.
Here is my entire test app code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white),
height: double.infinity,
width: double.infinity,
child: Center(
child: Text(
'Hello World',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32, fontWeight: FontWeight.bold, color: Colors.black),
),
),
);
}
}
There's now a plugin to do this, which is not a permanent thing as it is described as preliminary functionality before eventually being folded into the core libraries.
Using the plugin for now is still likely to be better than hard-coding directly modifying the native code, especially if you have multiple platforms you want to work on.
First add to the pubspec.yaml something like:
dependencies:
...
window_size:
git:
url: git://github.com/google/flutter-desktop-embedding.git
path: plugins/window_size
ref: 927f8cbc09b35d85245c095f2db8df9b186f6618
Using the specific Git reference to include this, as shown above, will give you good control over when you choose to pull updated code and make any changes this might entail.
You can then access various functions to set min/max window sizes, or frame, or get the current values, e.g.:
...
import 'dart:io'
import 'package:window_size/window_size.dart';
...
void main() {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
setWindowTitle("My Desktop App");
setWindowMinSize(Size(375, 750));
setWindowMaxSize(Size(600, 1000));
}
runApp(MyApp());
}
I hope this helps someone. I'll try and update this post when the real answer comes out. It seems likely that the interface will approximate what is presented in this library, but the feature set is likely to undergo some change.
Currently the only way to control the initial size is in native code (follow these issues: 1 and 2 to find out when that changes). You'd most likely want to set it in macos/Runner/MainFlutterWindow.swift.
It's not clear from your description whether you want to launch into full-screen mode, or just have a standard window the size of the client area of the screen; the code involved would be different depending on which you are trying to accomplish.
This package can help with it.
Size size = await DesktopWindow.getWindowSize();
print(size);
await DesktopWindow.setWindowSize(Size(500,500));
await DesktopWindow.setMinWindowSize(Size(400,400));
await DesktopWindow.setMaxWindowSize(Size(800,800));
await DesktopWindow.resetMaxWindowSize();
await DesktopWindow.toggleFullScreen();
bool isFullScreen = await DesktopWindow.getFullScreen();
await DesktopWindow.setFullScreen(true);
await DesktopWindow.setFullScreen(false);
I am not sure if this 100% valid, but I was looking for possibility to set window size. I have found package as #karora mentioned, but I wanted to only set window size and move on. So we can make it using xcode.
In project folder open Runner.xcodeproj:
macos -> Runner.xcodeproj
Then in Xcode project find MainMenu.xib then you can resize your flutter window.
You should be able to achieve this now within Dart code by using the window_size plugin.
The code to set initial window size could be something like:
#override
void initState() {
super.initState();
setWindowFrame(Rect.fromLTRB(1200.0, 500.0, 1800.0, 1125.0));
}
somewhere like your top-level stateful widget.
Though I should note that at the moment for me on Linux, the window frame sizing works, but positioning doesn't.
i need set default size for windows desktop app & this solution worked for me and cover the ios and linux platforms.
import 'package:desktop_window/desktop_window.dart'as window_size;
import 'dart:io';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
window_size.DesktopWindow.setMinWindowSize(Size(375, 750));
window_size.DesktopWindow.setMaxWindowSize(Size(600, 1000));
}
runApp(MyApp());
}
Related
I did to make a simple pokedex application for trying myself. I completed my project and I did not get any issue in android studio.Other hand, When I started my application, I cant see images to get in my project in emulator. Can anyone help me for this issue .
Can look at this extension.
https://github.com/AlejandroTaichu/Pokedex.git
I want to see images in my project when I was opened my project.I am new on programming so I cant fix that.
You have forgotten extension of image in your code
child: Image.asset("images/${pokemon.name}")),
Change to below code
child: Image.asset("images/${pokemon.name}.png")),
Or add image extension(.png) in names of pokeList
You need to change the image name(path) according to the assets image path include the image type.
Next you need to create a future and call future on Future Builder widget.
late final future = callPokemon();
class _PokemonHomepageState extends State<PokemonHomepage> {
Future<List<Pokemons>> callPokemon() async {
var pokeList = <Pokemons>[];
var p1 = Pokemons(pokeId: 1, name: "Charmender.png", health: 100, power: 250);
var p2 = Pokemons(pokeId: 2, name: "squirtle.png", health: 150, power: 300);
var p3 = Pokemons(pokeId: 3, name: "balbazar.png", health: 300, power: 500);
pokeList.add(p1);
pokeList.add(p2);
pokeList.add(p3);
return pokeList;
}
late final future = callPokemon();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar:
AppBar(title: const Text("POKEDEX"), backgroundColor: Colors.green),
body: FutureBuilder<List<Pokemons>>(
future: future,
builder: (context, snapshot) {
Made a pr on git, you can merge it
I suggest you to use flutter_gen (https://pub.dev/packages/flutter_gen) for assets. I recently found this package & its really helpful when using multiple images from assets.
With flutter_gen you can just setup few things one time & you can directly get image widgets from this package.
Setup flutter_gen
dart pub global activate flutter_gen
Add these runners in your dev dependencies
dev_dependencies:
build_runner:
flutter_gen_runner:
Setup path of generated assets file
flutter_gen:
output: lib/generated/
There are many options in this step. You can check their documentation.
Set image folder path
assets:
- assets/images/
Put your images in the path added
After doing these steps you just need to run
flutter packages pub run build_runner build
This file will generate an assets file name assets.gen.dart inside the lib/generated folder as we setup in step 3.
Note that you have to run this command whenever you change folder name or images to regerenated the assets.gen.dart
Thats it.
When you are done with these steps, you can directly get the images from this assets.gen.dart file like this
import 'package:flutter_boilerplate/generated/assets.gen.dart';
Padding(
padding: const EdgeInsets.all(20),
child: SizedBox(
height: 200, child: Assets.images.cat1.image(width: 200),
),
),
The plus benefit is that these assets provided widget support intellisense, so there is no chance for spelling mistake. Plus you directly get a widget from this with all the properties of default Image widget.
It also supports advance image types like svg, lottie, flare as well.
I need the screen in the test to look the same as on the physical device(or simulator). How can I do it? In my case device id Iphone SE.
I wrote a test that saves a screenshot to disk:
testWidgets('test', (WidgetTester tester) async {
final AutomatedTestWidgetsFlutterBinding binding = tester.binding;
binding.renderView.configuration = TestViewConfiguration(size: Size(640, 1136));
var widget = Scaffold(
appBar: AppBar(title: Text('title'),),
body: Column(children: <Widget>[
RaisedButton(
child: Text('button'),
onPressed: () {},)
],),
);
var key = new GlobalKey();
await tester.pumpWidget(
MaterialApp(home: RepaintBoundary(key: key, child: widget),),
);
await tester.pumpAndSettle();
await tester.runAsync(() async {
RenderRepaintBoundary boundary = key.currentContext.findRenderObject();
var image = await boundary.toImage();
var byteData = await image.toByteData(format: ImageByteFormat.png);
var pngBytes = byteData.buffer.asUint8List();
await File('screen.png').writeAsBytes(pngBytes);
});
});
if use ViewConfiguration with devicePixelRatio instead TestViewConfiguration, devicePixelRatio ignoring
MediaQuery too don work, if wrap MaterialApp
appbar and button less then on simulator
screen from test:
but expected(widgets scale):
You get the blocks instead of text because Flutter uses a specific test font (Ahem) that has all characters just blocks.
This makes it easier to render them equally on Linux (CI) and other platforms. I don't know if there are other reasons.
I also wasn't able to make images work in golden tests.
https://github.com/flutter/engine/pull/6913 was a recently merged fix to allow loading custom fonts in tests.
You can use flutter run --use-test-fonts to make Flutter use the Ahem font when you run the app on a real device so you can visualize how the test will look.
Related issues
https://github.com/flutter/flutter/issues/24405
https://github.com/flutter/flutter/issues/17910#issuecomment-445184463
I don't know if font's loaded this way work in golden tests though (they might still not work similar to images)
If you want to specify different screen sizes see (not tested myself) How to test Flutter widgets on different screen sizes?
Not sure if this suggestion is still of any value. I found it quite limited and the above suggestion probably works better) In Flutter Widget testing, how to make media.orientation to portrait?
In production mode, is there a way to force a full restart of the application (I am not talking about a hot reload at development time!).
Practical use cases:
At initialization process the application detects that there is no network connection. The lack of network connectivity might have prevented a correct start up (e.g. loading of external resource such as JSON files...).
During the initial handshaking, new versions of some important resources need to be downloaded (kind of update).
In both use cases, I would like the application to proceed with a full restart, rather than having to build a complex logic at the ApplicationState level.
You could wrap your whole app into a statefulwidget. And when you want to restart you app, rebuild that statefulwidget with a child that possess a different Key.
This would make you loose the whole state of your app.
import 'package:flutter/material.dart';
void main() {
runApp(
RestartWidget(
child: MaterialApp(),
),
);
}
class RestartWidget extends StatefulWidget {
RestartWidget({this.child});
final Widget child;
static void restartApp(BuildContext context) {
context.findAncestorStateOfType<_RestartWidgetState>().restartApp();
}
#override
_RestartWidgetState createState() => _RestartWidgetState();
}
class _RestartWidgetState extends State<RestartWidget> {
Key key = UniqueKey();
void restartApp() {
setState(() {
key = UniqueKey();
});
}
#override
Widget build(BuildContext context) {
return KeyedSubtree(
key: key,
child: widget.child,
);
}
}
In this example you can reset your app from everywhere using RestartWidget.restartApp(context).
The flutter_phoenix package is based on Rémi Rousselet's answer, making it even simpler.
void main() {
runApp(
Phoenix(
child: App(),
),
);
}
Then when you need to restart the app, just call:
Phoenix.rebirth(context);
I developed the restart_app plugin to restart the whole app natively.
Update:
For anyone who get this exception:
MissingPluginException(No implementation found for method restartApp on channel restart)
Just stop and rebuild the app.
You can also use the runApp(new MyWidget) function to do something similar
This is what this function does:
Inflate the given widget and attach it to the screen.
The widget is given constraints during layout that force it to fill the entire screen. If you wish to align your widget to one side of the screen (e.g., the top), consider using the Align widget. If you wish to center your widget, you can also use the Center widget
Calling runApp again will detach the previous root widget from the screen and attach the given widget in its place. The new widget tree is compared against the previous widget tree and any differences are applied to the underlying render tree, similar to what happens when a StatefulWidget rebuilds after calling State.setState.
https://docs.flutter.io/flutter/widgets/runApp.html
So simple package: flutter_restart
dependencies:
flutter_restart: ^0.0.3
to use:
void _restartApp() async {
FlutterRestart.restartApp();
}
I just want to add Regarding I have Tried #Remi answer which works great on most of the cases to restart the app. The only problem with the answer is that some things if you are doing Navigation route extensively you probably go to a state which It gives you an error like,
The method 'restartApp' was called on null.
To resolve this error you have to know the Context and use Navigator.of(context).pop(); multiples times back. For me, the solution is that just go to the initial route. It will inject all the states from a new. Where you want to restart just add this Line.
Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false);
If you want to only restart a specific widget then the Remi solution is awesome. Thanks for the solution Remi though. It help me understand states in flutter.
I have found Hossein's restart_app package also pretty useful for native restarts (not only on Flutter level).
To everyone having the MissingPluginException error, just reinstall the app again on the device, means that hot reload won't work. The app has native methods which need to compiled in the Android/iOS App.
I wanted to restart my app after logout.
so I used https://pub.dev/packages/flutter_phoenix (flutter phoenix).
It worked for me.
Install flutter_phoenix by running this command on your terminal inside your flutter app directory.
$ flutter pub add flutter_phoenix
Import it inside your "main.dart".
Wrap your root widget inside Phoenix.
runApp(
Phoenix(
child: MyApp()
));
Now you can call this wherever you want to restart your app :-
Phoenix.rebirth(context)
Note: flutter_phoenix does not restart the app on OS level, it only restarts the app on app level.
Thecnically this is not a restart but it will work for most of the scenarios:
// Remove any route in the stack
Navigator.of(context).popUntil((route) => false);
// Add the first route. Note MyApp() would be your first widget to the app.
Navigator.push(
context,
CupertinoPageRoute(builder: (context) => const MyApp()),
);
Follow the steps-
Go to your terminal and type in the following:
flutter pub add flutter_restart
This will update some dependencies in pubspec.yaml file.
Import the following package in whichever file you want to implement the restart code-
import 'package:flutter_restart/flutter_restart.dart';
Create a void function
void _restartApp() async {
await FlutterRestart.restartApp();
}
Write this wherever you want to start the app-
_restartApp();
I tried the above suggested methods and none of them worked and i was using getx.
so i ended up modified the accepted answer with a delay as a workaround and it works now.
class RestartAppWidget extends StatefulWidget {
RestartAppWidget({this.child});
final Widget child;
static void restartApp(BuildContext context) {
context.findAncestorStateOfType<_RestartAppWidgetState>().restartApp();
}
#override
_RestartAppWidgetState createState() => _RestartAppWidgetState();
}
class _RestartAppWidgetState extends State<RestartAppWidget> {
bool restarting = false;
void restartApp() async {
restarting = true; // restart variable is set to true
setState(() {});
Future.delayed(Duration(milliseconds: 300)).then((value) {
setState(() {
restarting = false; //restart variable is set to false
});
});
// setState(() {
// key = UniqueKey();
// });
}
#override
Widget build(BuildContext context) {
if (restarting) {
return SizedBox(); //an empty Sizedbox is displayed for 300 milliseconds you can add a loader if you want
}
return SizedBox(
child: widget.child,
);
}
}`
wrap the root widget with RestartAppWidget
runApp(RestartAppWidget(
child: MyApp(),
))
you can use this code to restart the app at flutter level
RestartAppWidget.restartApp(Get.context);
In production mode, is there a way to force a full restart of the application (I am not talking about a hot reload at development time!).
Practical use cases:
At initialization process the application detects that there is no network connection. The lack of network connectivity might have prevented a correct start up (e.g. loading of external resource such as JSON files...).
During the initial handshaking, new versions of some important resources need to be downloaded (kind of update).
In both use cases, I would like the application to proceed with a full restart, rather than having to build a complex logic at the ApplicationState level.
You could wrap your whole app into a statefulwidget. And when you want to restart you app, rebuild that statefulwidget with a child that possess a different Key.
This would make you loose the whole state of your app.
import 'package:flutter/material.dart';
void main() {
runApp(
RestartWidget(
child: MaterialApp(),
),
);
}
class RestartWidget extends StatefulWidget {
RestartWidget({this.child});
final Widget child;
static void restartApp(BuildContext context) {
context.findAncestorStateOfType<_RestartWidgetState>().restartApp();
}
#override
_RestartWidgetState createState() => _RestartWidgetState();
}
class _RestartWidgetState extends State<RestartWidget> {
Key key = UniqueKey();
void restartApp() {
setState(() {
key = UniqueKey();
});
}
#override
Widget build(BuildContext context) {
return KeyedSubtree(
key: key,
child: widget.child,
);
}
}
In this example you can reset your app from everywhere using RestartWidget.restartApp(context).
The flutter_phoenix package is based on Rémi Rousselet's answer, making it even simpler.
void main() {
runApp(
Phoenix(
child: App(),
),
);
}
Then when you need to restart the app, just call:
Phoenix.rebirth(context);
I developed the restart_app plugin to restart the whole app natively.
Update:
For anyone who get this exception:
MissingPluginException(No implementation found for method restartApp on channel restart)
Just stop and rebuild the app.
You can also use the runApp(new MyWidget) function to do something similar
This is what this function does:
Inflate the given widget and attach it to the screen.
The widget is given constraints during layout that force it to fill the entire screen. If you wish to align your widget to one side of the screen (e.g., the top), consider using the Align widget. If you wish to center your widget, you can also use the Center widget
Calling runApp again will detach the previous root widget from the screen and attach the given widget in its place. The new widget tree is compared against the previous widget tree and any differences are applied to the underlying render tree, similar to what happens when a StatefulWidget rebuilds after calling State.setState.
https://docs.flutter.io/flutter/widgets/runApp.html
So simple package: flutter_restart
dependencies:
flutter_restart: ^0.0.3
to use:
void _restartApp() async {
FlutterRestart.restartApp();
}
I just want to add Regarding I have Tried #Remi answer which works great on most of the cases to restart the app. The only problem with the answer is that some things if you are doing Navigation route extensively you probably go to a state which It gives you an error like,
The method 'restartApp' was called on null.
To resolve this error you have to know the Context and use Navigator.of(context).pop(); multiples times back. For me, the solution is that just go to the initial route. It will inject all the states from a new. Where you want to restart just add this Line.
Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false);
If you want to only restart a specific widget then the Remi solution is awesome. Thanks for the solution Remi though. It help me understand states in flutter.
I have found Hossein's restart_app package also pretty useful for native restarts (not only on Flutter level).
To everyone having the MissingPluginException error, just reinstall the app again on the device, means that hot reload won't work. The app has native methods which need to compiled in the Android/iOS App.
I wanted to restart my app after logout.
so I used https://pub.dev/packages/flutter_phoenix (flutter phoenix).
It worked for me.
Install flutter_phoenix by running this command on your terminal inside your flutter app directory.
$ flutter pub add flutter_phoenix
Import it inside your "main.dart".
Wrap your root widget inside Phoenix.
runApp(
Phoenix(
child: MyApp()
));
Now you can call this wherever you want to restart your app :-
Phoenix.rebirth(context)
Note: flutter_phoenix does not restart the app on OS level, it only restarts the app on app level.
Thecnically this is not a restart but it will work for most of the scenarios:
// Remove any route in the stack
Navigator.of(context).popUntil((route) => false);
// Add the first route. Note MyApp() would be your first widget to the app.
Navigator.push(
context,
CupertinoPageRoute(builder: (context) => const MyApp()),
);
Follow the steps-
Go to your terminal and type in the following:
flutter pub add flutter_restart
This will update some dependencies in pubspec.yaml file.
Import the following package in whichever file you want to implement the restart code-
import 'package:flutter_restart/flutter_restart.dart';
Create a void function
void _restartApp() async {
await FlutterRestart.restartApp();
}
Write this wherever you want to start the app-
_restartApp();
I tried the above suggested methods and none of them worked and i was using getx.
so i ended up modified the accepted answer with a delay as a workaround and it works now.
class RestartAppWidget extends StatefulWidget {
RestartAppWidget({this.child});
final Widget child;
static void restartApp(BuildContext context) {
context.findAncestorStateOfType<_RestartAppWidgetState>().restartApp();
}
#override
_RestartAppWidgetState createState() => _RestartAppWidgetState();
}
class _RestartAppWidgetState extends State<RestartAppWidget> {
bool restarting = false;
void restartApp() async {
restarting = true; // restart variable is set to true
setState(() {});
Future.delayed(Duration(milliseconds: 300)).then((value) {
setState(() {
restarting = false; //restart variable is set to false
});
});
// setState(() {
// key = UniqueKey();
// });
}
#override
Widget build(BuildContext context) {
if (restarting) {
return SizedBox(); //an empty Sizedbox is displayed for 300 milliseconds you can add a loader if you want
}
return SizedBox(
child: widget.child,
);
}
}`
wrap the root widget with RestartAppWidget
runApp(RestartAppWidget(
child: MyApp(),
))
you can use this code to restart the app at flutter level
RestartAppWidget.restartApp(Get.context);
All tutorials and documentation I've seen so far start of with importing flutter material. I am wondering is this an absolute requirement? What if I want to start with a plain canvas and build my own theme / widgets. Can I do this, if so what package should be used here so I get access to default widgets?
Although the answers here are correct, I want to add a few more points. To use raw widgets use import 'package:flutter/widgets.dart';
Here is a working example:
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(25.0),
child: Directionality(
textDirection: TextDirection.ltr,
child:Text("hello world",
style: TextStyle(
color: Color.fromRGBO(255, 255, 255, 1)
),
)));
}
}
The directionality is needed, the padding was added so that we see the message, otherwise it is masked by the menubar in phone.
Widgets in flutter makes the developers day easy. All the widgets are built on top dart:ui lib. It is up to you, to decide to use existing set of widgets or develop your ui from scratch. Flutter does not stop you from writing your own widgets.
You can find a few raw example of here, that does not use any widgets at all.
If you simple don't want only material widgets, then you can just build your own themed widgets with all other basic widgets and layouts available in flutter.
If you wanted to build few of your own widgets with a canvas and use it along with other widgets in flutter, you look into CustomPaint and CustomPainter widgets.
Hope this helped!
Just as Chandan Purohit answered, use import 'package:flutter/widgets.dart';. Flutter official gives a minimal app in Introduction to widgets as follows:
import 'package:flutter/material.dart';
void main() {
runApp(
const Center(
child: Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
),
);
}
Just change flutter/material.dart to flutter/widgets.dart, and you get a plain canvas to start.
Note: The color of Text is white by default.