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?
Related
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.
Inside the widget build function, there is a parameter called CONTEXT BUILD CONTEXT. What is its importance?
Is there an example to explain its importance?
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'), ); }}
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();
});
}
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();
I've been trying to make a Container move from the bottom of the screen to the middle when I click a button. However, I can't figure out how to properly execute the animation only when I press the button. Furthermore, it seems that when I call the _customWidget.startAnimation() method an error stating I called the function on void always happens. Here are my questions:
How do I access startAnimation() inside MyCustomWidget properly and how should I structure the code to only run the animation when I press the button?
Main.dart:
import 'package:flutter/material.dart';
import 'MyCustomWidget.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
MyCustomWidget _customWidget;
#override
void initState() {
super.initState();
_customWidget = MyCustomWidget();
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: MyCustomWidget(),
),
FloatingActionButton(
onPressed: () => {} //_customWidget.startAnimation() gives an error,
)
],
);
}
}
MyCustomWidget.dart:
import 'package:flutter/material.dart';
class MyCustomWidget extends StatefulWidget {
#override
_MyCustomWidgetState createState() => _MyCustomWidgetState();
startAnimation() {
debugPrint('is this where the function should be?');
}
}
class _MyCustomWidgetState extends State<MyCustomWidget>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<Offset> _offsetAnimation;
void startAnimation() {
debugPrint('or is it here?');
}
#override
void initState() {
super.initState();
//Following code should go in startAnimation() rather than letting it execute
//every time the object is created
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat(reverse: true);
_offsetAnimation = Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.5, 0.0),
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.elasticIn,
));
}
#override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: Container(
color: Colors.white,
height: 50,
width: 50,
),
);
}
#override
void dispose() {
super.dispose();
_animationController.dispose();
}
}
In Flutter, you access the child widgets using key. You also have to make the state public (remove the underscore from _MyCustomWidgetState)
So in the child:
class MyCustomWidget extends StatelessWidget {
final Key key;
MyCustomWidget(this.key) : super(key: key);
[...]
in the parent:
GlobalKey<MyCustomWidgetState> key = GlobalKey<MyCustomWidgetState>();
[...]
Center(
child: MyCustomWidget(key)
)
and calling the child (from parent):
key.currentState.startAnimation();
Tien's answer got my widget working correctly, here's how the two files look after the modifications:
Main.dart
import 'package:flutter/material.dart';
import 'MyCustomWidget.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GlobalKey<MyCustomWidgetState> _customWidgetKey =
GlobalKey<MyCustomWidgetState>();
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: MyCustomWidget(_customWidgetKey),
),
FloatingActionButton(
onPressed: () => _customWidgetKey.currentState.show(),
)
],
);
}
}
MyCustomWidget.dart:
import 'package:flutter/material.dart';
class MyCustomWidget extends StatefulWidget {
final Key key;
MyCustomWidget(this.key) : super(key: key);
#override
MyCustomWidgetState createState() => MyCustomWidgetState();
}
class MyCustomWidgetState extends State<MyCustomWidget>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation<Offset> _offsetAnimation;
void show() {
setState(() {
_animationController.animateTo(1.0);
});
}
void hide() {
setState(() {
_animationController.animateTo(0.0);
});
}
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
);
_offsetAnimation = Tween<Offset>(
begin: Offset(0.0, 40),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOutQuint,
));
}
#override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: Container(
child: FloatingActionButton(
backgroundColor: Colors.white,
onPressed: () => hide(),
),
),
);
}
#override
void dispose() {
super.dispose();
_animationController.dispose();
}
}
This gets you a button which brings up a button when pressed. Clicking the second button sends it down. This whole thing is going to be useful to make custom widgets pop up and down!