I have added a Video to visualize my problem better: https://streamable.com/wdhna2
The problem is that my images load slowly, even I added a precache method and a splash screen. On first boot, the problem isn't that big, maybe because of the precache.
here I'm implementing the precache method:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
loadImage(context); <--- Method call
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
and here is my precache method (just a snipped, not for all pictures):
import 'package:flutter/material.dart';
void loadImage(context){
precacheImage(const AssetImage("assets/widgetsImages/bmi.jpg"), context);
precacheImage(const AssetImage("assets/widgetsImages/calc.webp"), context);
precacheImage(const AssetImage("assets/widgetsImages/chat.webp"), context);
}
I also tried to add a splash screen with the flutter_native_splash package, but this wouldn't fix the problem that the images load slowly after I close and reopen the app, without clearing my RAM. Anyway, here is the code for that:
Future<void> main() async {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
and the end of the splashscreen when the first window opens:
class _NutriWidgetState extends State<NutriWidget> {
#override
void initState() {
super.initState();
FlutterNativeSplash.remove();
}
Do you have an idea how I could load the images faster? Do I do something wrong?
try
image.assets("assets/widgetsImages/bmi.jpg")
think you can not call directly into the widget builder
you have to wrap it into Scaffolds
or return your method not call this
return loadImage(context)
Related
My function is as follows:
void function() async {
…
}
I used the above function in Widget build(BuildContext context).
Actually, I want it to be Future<void> function() async instead of void function() async.
However, I can't use await in Widget build(BuildContext context), so I can't use Future<void> function() async because Future requires await.
I shouldn't use FutureBuilder or then because I don't want to get the data in the function, I just want to run the function.
Appreciate if someone can advise. Thank you in advance!
You can define your function as future & call it in initState of StatefulWidget (without await)
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future<void> myFutureFunction() async {
// some future work with
}
#override
void initState() {
super.initState();
// this will be called once, when this widget is apear to the screen
myFutureFunction();
}
#override
Widget build(BuildContext context) {
return SizedBox();
}
}
build method can run up to 60(maybe more with the newest phones)times per second, so it's not a good idea to run any heavy computation or API call in the build method. It's simply for building(widgets).
You may want to rethink your app architecture if you think you must.
Consider bloc pattern or just checkout other lifecycle methods for stateful widgets. This article has a list of them.
As for the question, async functions technically don't require you to await them. You can just call them without adding await in front of them.
If you have a warning, it might be coming from lint rules. Related rule.
I had firebase dynamic links integrated and working fine in my app and later i changed to use go_router and now i don't know what i should do to get it working or how to handle it.
The way i imagined it would be is that the FB dynamic link path will be the same as the path to the page in GoRouter routes, and go_router will redirect to the page automatically but i don't think that is how it works and i can't find any resources for this.
So the question is how to use Firebase DynamicLinks with go_router?
this is how I did it, looks like working fine :)
For when the app is in terminated mode:
Future main() async {
...
// Closed state: getInitialLink is Used
final PendingDynamicLinkData? initialLink =
await FirebaseDynamicLinks.instance.getInitialLink();
...
then through runApp(MtApp(initialRoute: initialLink)) pass it to GoRouter.initialLocation field or GoRouter.redirect function, depending on how you use it.
For when the app is in background:
wrap your top widget with a statefulWidget your created like:
class AHDynamicLinksManager extends
StatefulWidget {
final Widget child;
const AHDynamicLinksManager({required this.child, Key? key})
: super(key: key);
#override
State<AHDynamicLinksManager> createState() => _AHDynamicLinksManagerState();
}
class _AHDynamicLinksManagerState extends State<AHDynamicLinksManager> {
#override
void initState() {
super.initState();
FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) {
String goingTo = dynamicLinkData.link.path;
GoRouter.of(context).go(goingTo);
}).onError((error) {
GoRouter.of(context).go("/errorpage/$error");
});
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
Hope it helped!
I am trying to wait till amplify configuration is done then load the login screen. Even though state seems to be getting updated I am still getting the loadinscreen. Why is that?
I am not sure if setState is proper method on the init : Importance of Calling SetState inside initState
As per the doc : https://docs.amplify.aws/start/getting-started/integrate/q/integration/flutter/#configure-amplify
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isAmplifyConfigured = false;
late AmplifyAuthCognito auth;
#override
void initState() {
_initializeApp();
super.initState();
}
Future<void> _initializeApp() async {
await _configureAmplify();
setState(() {
_isAmplifyConfigured = true;
});
}
Future<void> _configureAmplify() async {
auth = AmplifyAuthCognito();
try {
await Amplify.addPlugin(auth);
await Amplify.configure(amplifyconfig);
} on AmplifyAlreadyConfiguredException {
print(
'Amplify was already configured. Looks like app restarted on android.');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: AppRoutes.onGenerateRoute,
initialRoute: _isAmplifyConfigured
? LoginScreen.routeName
: LoadingScreen.routeName,
);
}
}
I think the issue is with you trying to reassign your initialRoute. I'm not super familiar with this property, but given the name I assume this is set once and is not rebuilt, not even when the state changes. It would make sense, also, because the rest of your code sounds like it should work.
Before trying anything else, I'd recommend you move your logic to initialize Amplify to the LoginScreen, and having its body depend on the _isAmplifyConfigured boolean value. So show spinner if it's false, and show Login fields when it's true.
Even better would be to create a HomeScreen, so you can keep this Amplify initialization at the bottom of your app's stack. And then have your HomeScreen either show the Login widgets, the home screen of your app, or a loading state.
I'm making a website and I would like to show a loading_page until the home_page is loaded and then transition from one to the other as soon as possible (no fixed timers).
There are multiple ways to do this (ie., using the simplest setState, Streams, multiple packages for state management, just to name a few). I'll give you a simple example just by using a StatefulWidget where you call your API on initState and then navigate when you're done to your new screen.
class LoadingPage extends StatefulWidget {
const LoadingPage({Key? key}) : super(key: key);
#override
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<LoadingPage> {
#override
void initState() {
super.initState();
_fetchFromAPI();
}
Future<void> _fetchFromAPI() async {
// Call some API, do anything you want while loading
Navigator.pushReplacementNamed(context, '/home_page');
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: const CircularProgressIndicator(),
);
}
}
You can use future builder for this purpose.
Have a look at: https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
You can fetch the data as snapshot and use the snapshot.hasdata to check if data is being received or not and till then you can show CircularProgreswIndicator() to show the loading..
What is the best way to dynamically do screen rotation in Flutter for few of the screens and not affect to other screens?
So i tried two ways, with mixins. (This way stackoverflow ). It works initially, for the first enter and leave screen, but when I do re-run again some of screen which should be landscape again, it's fixed in portrait and thats all, until i re-run the app.
And tried directly, with setting preferred orientation. (This way stackoverflow This way mess-up whole app even if i just unlock rotation on build/initState (tried both) on one screen, and lock it on same screen on dispose.
For example, i need camera screen rotated with whole UI, and i have screen to edit the image, and i need that screen in the portrait, and there problems shows up.
UPDATE: So here is the link with code with mixins try. I created mixin which enables rotation in that screen, and on dispose, lock rotation again. CODE
And code here:
mixin RotationEnabledStatefulModeMixin<T extends StatefulWidget> on
State<T> {
#override
Widget build(BuildContext context) {
_enableRotation();
return null;
}
#override
void dispose() {
_portraitModeOnly();
print("RotationEnabledStatefulModeMixin -> disposed!");
}
}
void _portraitModeOnly() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
void _enableRotation() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
//this is screen where i need landscape only
class TakePictureScreen extends StatefulWidget {
final CameraDescription camera;
TakePictureScreen(
{Key key, #required this.camera, this.report, this.sectionIndex})
: super(key: key);
#override
TakePictureScreenState createState() => TakePictureScreenState();
}
class TakePictureScreenState extends State<TakePictureScreen> with
RotationEnabledStatefulModeMixin<TakePictureScreen>{
CameraController _controller;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
super.build(context);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
}