Webview with pull down refresh - xcode

I'm starting in Flutter and I don't know how to refresh the Webview with the scroll down.
This is my current code. The Webview is displayed normally, but the scroll down doesn't refresh.
I already tried using inappwebview and pull_to_refresh, but nothing works.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter_launcher_icons/constants.dart';
import 'package:flutter/widgets.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'WebView Example',
theme: ThemeData.light(),
home: WebViewExample(),
);
}
}
class WebViewExample extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: WebView(
initialUrl: 'https://stackoverflow.com',
javascriptMode: JavascriptMode.unrestricted,
),
);
}
}
Anyone who can provide a practical, working example of this implementation? Any help will be appreciated.

Related

Flutter: How do I open "local" files?

I am trying to figure out how to access "local" files in my Flutter Android app. What I mean by "local" is a file that has been bundled in with the app package. I am using Android Studio as my IDE.
I created an "assets" directory in the base of my project, and added a txt file to that directory.
I then added the following to my pubspec.yaml file and did a pub get:
assets:
- assets/data.txt
Here is my main.dart code:
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.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 File Test'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _buttonPressed() {
File file = File('assets/data.txt');
Future<String> futureContent = file.readAsString();
futureContent.then((c) => print(c));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
floatingActionButton: FloatingActionButton(
onPressed: _buttonPressed,
tooltip: 'Press me!',
child: const Icon(Icons.add),
),
);
}
}
When I run the app and press the button, I get the following error:
E/flutter (15392): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: FileSystemException: Cannot open file, path = 'assets/data.txt' (OS Error: No such file or directory, errno = 2)
E/flutter (15392): #0 _File.open.<anonymous closure> (dart:io/file_impl.dart:356:9)
E/flutter (15392): <asynchronous suspension>
E/flutter (15392):
What am I missing?

How to auto start animated icon

My application has a stateful widget which is the profile area, I would like to display an animated icon indicating to the user that is possible to scroll the screen, I want to use the animated icon, how to auto animate an AnimatedIcon as soon the Profile screen loads, thanks.
Obs.: The play_pause is just a placeholder for an animated icon
import 'package:flutter/material.dart';
void main() {
runApp(Profile());
}
class Profile extends StatefulWidget {
#override
ProfileState createState() {
return ProfileState();
}
}
class ProfileState extends State<Profile> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: AnimatedIcon(
progress: AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
reverseDuration: Duration(milliseconds: 400),
),
icon: AnimatedIcons.play_pause,
),
)
)
);
}
}
You have to create an instance of AnimationController and initialize it on the initState. Then you can start the animation by calling animateTo method.
import 'package:flutter/material.dart';
void main() {
runApp(Profile());
}
class Profile extends StatefulWidget {
#override
ProfileState createState() {
return ProfileState();
}
}
class ProfileState extends State<Profile> with TickerProviderStateMixin {
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
);
_animationController.animateTo(1.0);
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: AnimatedIcon(
progress: _animationController,
icon: AnimatedIcons.play_pause,
),
),
),
);
}
}
you could do that using the animationController
_animationController.forward(); /// to start the animation
You can start your animation after the build method executes by calling it like this.
#override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((​_){
_animationController.forward();
});
}

How to dismiss any open dialog in Flutter app, when app goes to background

In my Flutter app I have lots of pop up dialogs, but I need to dismiss any open dialog when app goes to background (user switches to another app).
I know about Lifecycle, but it's not easy to implement it for all dialogs.
Did you try Navigator.popUntil on the life cycle?.
Navigator.popUntil(context, (route) => !(route is PopupRoute));
Example:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
#override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
void _showDialogs() {
showDialog(
context: context,
builder: (context) => AlertDialog(title: Text("Dialog 1")),
);
showDialog(
context: context,
builder: (context) => AlertDialog(title: Text("Dialog 2")),
);
showDialog(
context: context,
builder: (context) => AlertDialog(title: Text("Dialog 3")),
);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text("show multiple dialogs"),
onPressed: _showDialogs,
),
),
);
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused)
Navigator.popUntil(context, (route) => !(route is PopupRoute));
}
}
Navigator.of(context,rootNavigator:true).pop();

Flutter - run a function every time the page changes

I want to run a function every time the page changes in my Flutter application.
Ideally, I don't want to call this function in initState of every page, as sometimes people can forget to add the call in a new page.
Think of it as middleware - be basically before the page loads etc, some code needs to run.
Updated code for review
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:myapp/pages/login_page.dart';
import 'package:myapp/pages/dashboard_page.dart';
import 'package:myapp/styles/constants.dart';
import 'package:myapp/services/auth_service.dart';
Future<void> main() async {
// create a auth service instance
AuthService authService = AuthService(secureStorage: FlutterSecureStorage());
bool isLoggedIn = await authService.isUserLoggedIn();
// run the app
runApp(MyApp(
isLoggedIn: isLoggedIn,
));
}
class MyApp extends StatefulWidget {
final bool isLoggedIn;
MyApp({this.isLoggedIn});
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with RouteAware {
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
#override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context));
}
#override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
#override
void didPush() {
print('didPush');
}
#override
void didPopNext() {
print('didPopNext');
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'App NAME',
theme: ThemeData(
primarySwatch: Colors.green,
primaryColor: kPrimeColour,
),
home: widget.isLoggedIn == true ? DashboardPage() : LoginPage(),
navigatorObservers: [routeObserver],
);
}
}
You can use implementation method didChangeDependencies this function called after initState,
flutter doc :
Subclasses rarely override this method because the framework always calls build after a dependency changes. Some subclasses do override this method because they need to do some expensive work (e.g., network fetches) when their dependencies change, and that work would be too expensive to do for every build.
Link
#override
void didChangeDependencies() {
super.didChangeDependencies();
// set your stuff here
}
You can use inheritance
abstract class MyState<T extends StatefulWidget> extends State {
#override
void initState() {
super.initState();
//YOUR CHANGE PAGE METHOD HERE
}
}
class YellowBird extends StatefulWidget {
const YellowBird({ Key key }) : super(key: key);
#override
_YellowBirdState createState() => _YellowBirdState();
}
class _YellowBirdState extends MyState<YellowBird> {
#override
Widget build(BuildContext context) {
return Container(color: const Color(0xFFFFE306));
}
}

How can I control animations in Flutter from outside?

Passing state down to widgets is easy. I have a StatefulWidget that contains an animation with its controller. I need to be able to trigger the animation from another widget higher in my widget tree.
My MainApp should trigger the animation using a button.
As I understand AnimationController only has an imperative API. I can call controller.forward() or controller.reverse(). But to do this I need to expose the controller to my MainApp.
What I currently do is to keep a global variable of my state around.
class MainApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
...
body: new LogoWidget(),
);
}
_startAnimation() {
_state.restartAnimation();
}
}
_LogoWidgetState _state; // yuk!
class LogoWidget extends StatefulWidget {
_LogoWidgetState createState() {
_state = _LogoWidgetState();
return _state;
}
}
class _LogoWidgetState extends State<LogoWidget>
with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
restartAnimation() {
controller.value == 1.0 ? controller.reverse() : controller.forward();
}
...
}
(full sourcecode here)
What is a better way to deal with this?
You don't need _LogoWidgetState _state; // yuk! out in the middle of nowhere, but you can try:
create LogoWidget _myBody = LogoWidget(), and use that for your body:
similarily, apply with final _LogoWidgetState _state = _LogoWidgetState()
then call it as _myBody._state.restartAnimation()
Your sample, modified:
class MainApp extends StatelessWidget {
LogoWidget _myBody = LogoWidget(); //<---
#override
Widget build(BuildContext context) {
return new Scaffold(
...
body: _myBody, //<---
);
}
_startAnimation() {
_myBody._state.restartAnimation(); //<---
}
}
class LogoWidget extends StatefulWidget {
final _LogoWidgetState _state = _LogoWidgetState(); //<---
_LogoWidgetState createState() {
return _state;
}
}
But if you think _myBody._state.restartAnimation() is too long, you can shorten it with:
class LogoWidget extends StatefulWidget {
final _LogoWidgetState _state = _LogoWidgetState(); //<---
void restartAnimation() { //<---
_state.restartAnimation();
}
_LogoWidgetState createState() {
return _state;
}
}
Then just use _myBody.restartAnimation()
Here's some relevant posts:
call method in one stateful widget from another stateful widget - Flutter
Flutter: Call a function on a child widget's state

Resources