Flutter accelerometer/gyroscope sensor lag - ios

I've been trying to implement a gyroscope image viewer using the sensors package, however, the result seems to be very laggy. I have found a similar project on YouTube which is trying to achieve a similar goal, but as you can see in the video the animation is also very laggy.
The following code is simply outputting the data from the event, I notice how the data is being updated lags like 50ms in between updates.
Is there a way to smoothen the animation or update the data faster? Or is this a Flutter limitation?
NOTE:
I have tried --release version as suggested by other posts but the result stays the same.
import 'package:sensors/sensors.dart';
class MyGyro extends StatefulWidget {
final Widget child;
MyGyro({this.child});
#override
_MyGyroState createState() => _MyGyroState();
}
class _MyGyroState extends State<MyGyro> {
double gyroX = 0;
double gyroY = 0;
#override
void initState() {
super.initState();
gyroscopeEvents.listen((GyroscopeEvent event) {
setState(() {
gyroX = ((event.x * 100).round() / 100).clamp(-1.0, 1.0) * -1;
gyroY = ((event.y * 100).round() / 100).clamp(-1.0, 1.0);
});
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 100,
width: 100,
child: Transform.translate(
offset: Offset(gyroY, 0),
child: Container(
child: Center(
child: Column(
children: [Text("X: ${gyroX}"), Text("Y: ${gyroY}"),],
),
),
),
),
);
}
}

I have found that is purely the problem of the sensors package I was using, either they have hard coded a slower interval when listening to the sensor event, or they are just using the default interval by the IOS channel.
So, I have found another package called flutter_sensors which had solved the problem. It's a very simple API to access the sensor events, but it allows you to change the interval.

Related

How to make flutter widgets adaptive to different screen sizes

I`m using width and height params of Container to determine widget size. but the widget is not adaptive if tested on other devices. I came from native android where i used to use density independent pixels(dp) that is adaptive to any screen size. what is the equivalent to dp in flutter ?
I dont want to use MediaQuery every time to calculate screen width and height.
You can use the SizeBox.expand widget to let your widget expand to take the available space regardless of size documentation
SizedBox.expand(
child:MyButton(),
),
And if you want to keep an aspect ratio regardless of screen size you can use the AspectRatio widget documentation
AspectRatio(
aspectRatio: 3/2,
child:MyButton(),
),
If your widgets are just in a row or column and you want to add weights among them to fill the spaces you can use the Expanded widget
Expanded(
flex: 1,//weight for the widget
child: Container(
color: Colors.amber,
height: 100,
),
)
,
You can set the size of your UI widgets this way:
width: 100.0 * MediaQuery.of(context).devicPixelRatio ,
the function MediaQuery.of(context).devicPixelRatio will return the actual number of pixel in each logical pixel, so you'll be sure that the same 100.0 pixel on your test device are typical to those of the user whatever screen density they have.
i applied this way :
class SizeConfig {
static MediaQueryData _mediaQueryData;
static double screenWidth;
static double screenHeight;
static double blockSizeHorizontal;
static double blockSizeVertical;
void init(BuildContext context) {
_mediaQueryData = MediaQuery.of(context);
screenWidth = _mediaQueryData.size.width;
screenHeight = _mediaQueryData.size.height;
blockSizeHorizontal = screenWidth / 100;
blockSizeVertical = screenHeight / 100;
}
}
class HomeScreen extends StatelessWidget { #override Widget
build(BuildContext context) { SizeConfig().init(context); … } }
#override
Widget build(BuildContext context) {
return Center(
child: Container(
height: SizeConfig.blockSizeVertical * 20,
width: SizeConfig.blockSizeHorizontal * 50,
color: Colors.orange,
),
);
}
https://medium.com/flutter-community/flutter-effectively-scale-ui-according-to-different-screen-sizes-2cb7c115ea0a

Does using const in the widget tree improve performance?

When creating a widget tree, will inserting const before static widgets improve performance?
ie
child: const Text('This is some text');
vs
child: Text('This is some text');
I know that, with Dart 2, const is optional and will be inserted automatically is some places. Is this one of those situations? If it isn't, will using const reduce memory usage/improve performance?
Thanks for your answers!
It is a small performance improvement, but it can add up in larger apps or apps where the view is rebuilt often for example because of animations.
const reduces the required work for the Garbage Collector.
You can enable some linter rules in analysis_options.yaml that tell you when you should add const because it's not inferred but would be possible like
http://dart-lang.github.io/linter/lints/prefer_const_constructors.html
http://dart-lang.github.io/linter/lints/prefer_const_declarations.html
http://dart-lang.github.io/linter/lints/prefer_const_literals_to_create_immutables.html
or that reminds you when you use const but it is inferred anyway
http://dart-lang.github.io/linter/lints/unnecessary_const.html
See also https://www.dartlang.org/guides/language/analysis-options
In the case of Flutter, the real gain with const is not having less instantiation.
Flutter has a special treatment for when the instance of a widget doesn't change: it doesn't rebuild them.
Consider the following:
Foo(
child: const Bar(
child: Baz()
),
)
In the case of build method being called again (setState, parent rebuild, Inheritedwidget...), then due to the const for Bar subtree, only Foo will see its build method called.
Bar will never get rebuilt because of its parent, because Flutter knows that since the widget instance didn't change, there's nothing to update.
Update:
I noticed I received an upvote lately, and I must say that I'm not confident in my tests below but that's all I got. So someone better run a better test.
I've ran some test to see if it makes a difference.
The tests are heavily based on the ones done in this article.
For the tests, there are 300 containers with text inside moving randomly on the screen. Something you wouldn't see in a day to day app.
For my results there is no difference in frame per second and there is no difference in memory usage except that the Garbage collector seems to run more often when not using const. Again, the FPS were about the same.
Imo, the performance boost is negligible and sounds like preemptive optimization. However there is no deeply nested chain of widgets in the test, but I don't see how that would make a difference. The article above seems to say there is a small one, but that's not what my tests show.
I've a card like this (this is the const version):
import 'package:flutter/material.dart';
class MyCard extends StatelessWidget {
const MyCard();
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
margin: const EdgeInsets.all(8.0),
height: 100,
width: 100,
color: Colors.red,
child: const Text('Hi'),
),
);
}
}
that's rendered 300 times and moving on the screen randomly.
This is the widget that makes them move
import 'package:flutter/material.dart';
import 'dart:math';
import 'dart:async';
import './my-card.dart';
class MovingContainer extends StatefulWidget {
#override
_MovingContainerState createState() => _MovingContainerState();
}
class _MovingContainerState extends State<MovingContainer> {
final Random _random = Random();
final Duration _duration = const Duration(milliseconds: 1000);
Timer _timer;
double _top = 0;
double _left = 0;
#override
void initState() {
super.initState();
initMove();
}
void initMove() {
_timer = Timer.periodic(
_duration,
(timer) {
move();
},
);
}
void move() {
final Size size = MediaQuery.of(context).size;
setState(() {
_top = _random.nextInt(size.height.toInt() - 100).toDouble();
_left = _random.nextInt(size.width.toInt() - 100).toDouble();
});
}
#override
void dispose() {
_timer.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return AnimatedPositioned(
top: _top,
left: _left,
child: const MyCard(),
duration: _duration,
);
}
}
Note: I'm new to flutter, and so are many others because it's a relatively new framework. Therefor my tests could very well be wrong, don't take it as gospel. Also don't take it as gospel when you read an article titled << Number One Perf gain on Flutter >>. I've yet to see actual proof there is a perf gain.
When we use setState() Flutter calls the build method and rebuilds
every widget tree inside it. The best way to avoid this is by using
const costructors.
Use const constructors whenever possible when building your own
widgets or using Flutter widgets. This helps Flutter to rebuild only
widgets that should be updated.
So if you have a StatefulWidget and you are using setState((){}) to
update that widget and you have widgets like:
class _MyWidgetState extends State<MyWidget> {
String title = "Title";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: <Widget>[
const Text("Text 1"),
const Padding(
padding: const EdgeInsets.all(8.0),
child: const Text("Another Text widget"),
),
const Text("Text 3"),
],
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
setState(() => title = 'New Title');
},
),
);
}
}

How to Convert SizeTransition to FadeTransition for Flutter Codelab

I'm new to Flutter and Dart. Hopes to get some guide on a tutorial exercise I'm stuck.
I'm following Flutter Codelab https://codelabs.developers.google.com/codelabs/flutter/index.html?index=..%2F..index#6 and able to do everything.
There's an exercise it ask us to do that is
Create a fade-in animation effect by wrapping the Container in a FadeTransition widget instead of a SizeTransition.
The code as below
#override
Widget build(BuildContext context) {
return new SizeTransition(
sizeFactor: new CurvedAnimation(
parent: animationController, curve: Curves.easeOut),
axisAlignment: 0.0,
child: new Container(
// ... other codes ...
),
);
}
So I change to FadeTransition, which requires opacity of type Animation<Double>
#override
Widget build(BuildContext context) {
return new FadeTransition(
opacity: animation
child: new Container(
// ... other codes ...
),
);
}
How could I create or send in the animation? (the above code will have animation unrecognizable).
You can try this
opacity: Tween<double>(
begin: 0.0,
end: 1.0,
).animate(animationController),
CurvedAnimation is used for non-linear animation.
See more detail here https://flutter.dev/docs/development/ui/animations/tutorial
Found the answer, by referring to https://proandroiddev.com/getting-your-hands-dirty-with-flutter-basic-animations-6b9f21fa7d17 and modify accordingly.
So to have FadeTransition, basically just replace
opacity: animation
with
opacity: new CurvedAnimation(parent: animationController, curve: Curves.easeIn),
This is not ideal as every time a message is inserted, it is creating a new CurveAnimation, but for the sake of concise solution, I make it so.

How to extend PageView to both sides with builder?

Using PageView.builder I can get an infinite list of pages, but only in one direction, i.e. it is finite in the other direction!
The default scrollDirection of a PageView is Axis.horizontal. So what I mean is that in the regular case I can only scroll infinitely to the right, but not to the left.
I want to be able to scroll infinitely in both directions. I have not found a way to do this, especially, because I would expect the itemBuilder to give out negative indices then, which I have never seen. That leads me to wondering whether this is implemented at all, but I am open to custom solutions and will try to come up with something aswell.
There's no official way of having an infinite scroll in both directions.
But you can instead use PageController's initialPage property. Setting it to an absurdly big value. And then use this value as your "index 0".
class MyHomePage extends StatelessWidget {
final PageController pageController = new PageController(initialPage: 4242);
#override
Widget build(BuildContext context) {
return new Scaffold(body: new PageView.builder(
controller: pageController,
itemBuilder: (context, _index) {
final index = _index - 4242;
return new Container(
margin: const EdgeInsets.all(9.0),
color: Colors.red,
child: new Center(
child: new Text(index.toString()),
),
);
},
));
}
}
I solved it pretty straight forward. Honestly, I must have been out of my mind writing the question and issueing the bounty.
// number is irrelevant
final initialPage = (
.161251195141521521142025 // :)
* 1e6,).round();
final itemCount = getSomeItemCount();
PageView.builder(
pageController: PageController(
initialPage: initialPage,
),
itemBuilder: (context, page) {
final index = itemCount - (initialPage - page - 1) % itemCount - 1;
return getPageContent(index);
},
);
I am not sure if I should give credit to Rémi Rousselet because I was using this method before he proposed his answer. I just wanted to mention him because this question is getting undeserved traffic and he helped me to solve my problem :)

How to display an animated picture in Flutter?

I want to display an animated picture, whatever its format, in Flutter. The fact is that currently there seems to be only one solution available, video_loader. This works only on full screen, but it doesn't fit my use case.
Any idea on how I could sort this out?
Now, Image widget Supports GIF. (April 18)
For Ex.
new Image(image: new AssetImage("assets/ajax-loader.gif"))
You can split the frames into separate images using https://ezgif.com/split and add them as assets in your pubspec.yaml.
Then use an Animation<int> to select the correct frame to display. Make sure to set gaplessPlayback: true to avoid flickering.
For example, the following code displays the frames of an animated GIF that was created by Guillaume Kurkdjian.
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
theme: new ThemeData.dark(),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController _controller;
Animation<int> _animation;
#override
void initState() {
_controller = new AnimationController(vsync: this, duration: const Duration(seconds: 5))
..repeat();
_animation = new IntTween(begin: 0, end: 116).animate(_controller);
}
Widget build(BuildContext context) {
return new Scaffold(
body: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new AnimatedBuilder(
animation: _animation,
builder: (BuildContext context, Widget child) {
String frame = _animation.value.toString().padLeft(3, '0');
return new Image.asset(
'assets/frame_${frame}_delay-0.04s.png',
gaplessPlayback: true,
);
},
),
new Text('Image: Guillaume Kurkdjian', style: new TextStyle(fontStyle: FontStyle.italic)),
],
),
);
}
}
2021 Update
As of now flutter does supports playing gif files using the Image widget.
Image.asset('assets/logo.gif')
But there's a problem with current way of loading gif in flutter. The gif plays in a loop and you can't stop the gif after playing it once. There are other ways of showing animated pictures using Rive and Lottie and both of them comes with a pretty well maintained flutter package that gives lots of features out of the box.
Workaround :
Convert your gif to mp4 (Gif to mp4)
Convert mp4 to Lottie json (Mp4 to Json)
Upload your Lottie json to lottiefiles.com or add to your assets folder
Use Lottie package to load your animation
Example from Lottie package docs :
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView(
children: [
// Load a Lottie file from your assets
Lottie.asset('assets/LottieLogo1.json'),
// Load a Lottie file from a remote url
Lottie.network(
'https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json'),
// Load an animation and its images from a zip file
Lottie.asset('assets/lottiefiles/angel.zip'),
],
),
),
);
}
}
For sure this is not the most ideal way of loading a gif as this is just a workaround. You can simply use an Image widget if you're not doing much with your gif. But if you will use Lottie then you get lots of things that you can do with your gif with much more control.
In order to run gif animation only once, there are 2 solutions.
First solution.
List<int> listGifDuration = [0,0,22,26,31,27,30,29,29,23,29,24,25,27,33,33,29,29];
List<int> listGifDurationDs = [0,0,1,0,0,0,0,0,0,0,0,0,0,0,5,2,5,0];
List<double> listGifFrames = [0,0,315,389,310,294,435,423,425,331,425,360,365,395,309,384,426,435];
strgif = "assets/gif/motion-all.gif"
fetchGif(AssetImage(strgif)).then((value) {
controller= GifController(vsync: this,duration: Duration(seconds: listGifDuration[widget.storyid]));
controller.addListener(() => setState(() {}));
TickerFuture tickerFuture = controller.repeat(min:0,max:listGifFrames[widget.storyid],period:Duration(seconds: listGifDuration[widget.storyid]));
tickerFuture.timeout(Duration(seconds: listGifDuration[widget.storyid]), onTimeout: () {
controller.forward(from: 0);
controller.stop(canceled: true);
});
});
2nd solution.
Convert the property of the gif file from the infinite loop to 1 loop.
Please use following link to convert gif file looping count.
https://ezgif.com/loop-count
and then
child: new Image.asset(strgif),
We can use Image widget to load any type of image whether it is a normal image or the gif.
We can load them from our asset as well as from network with the help of Image widget
Image.asset('name');
Image.file(file);
Image.memory(bytes);
Image.network('src');
There are some dependency for load the gif also

Resources