How do I make a Looping Function in flutter - function

I want to make a widget(a fan) spin around untill the user clicks it.
And for that, I thought I was gonna use a function, but then the question is;
How do I make a looping function, that stoppes when a bool = false?
This is my current function (that doesn't loop):
#override
void initState() {
super.initState();
angleController = AnimationController(vsync: this, duration: Duration(milliseconds: 230));
angleController .addListener(() {
setState(() {
fanAngle = angleController.value * 90 / 360 * pi * 2;
});
});
}
And the GestureDetector function:
void fanRotation() {
if(angleController.status == AnimationStatus.completed){
angleController.stop();
fanState = false;
} else if (angleController.status == AnimationStatus.dismissed) {
angleController.forward();
fanState = true;
}
}
}
I want it to have a continuous loop, so no stopping and starting again.

You can copy paste run full code below
You can directly call angleController.repeat() in initState() and call angleController.stop() when click fan
code snippet
#override
void initState() {
super.initState();
angleController =
AnimationController(vsync: this, duration: Duration(seconds: 3));
angleController.repeat();
}
...
GestureDetector(
onTap: () {
angleController.stop();
},
child: Icon(
Icons.forward,
color: Colors.pink,
size: 100.0,
)),
working demo
full code
import 'package:flutter/material.dart';
import 'dart:math';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
AnimationController angleController;
#override
void initState() {
super.initState();
angleController =
AnimationController(vsync: this, duration: Duration(seconds: 3));
angleController.repeat();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AnimatedBuilder(
animation: angleController,
builder: (_, child) {
return Transform.rotate(
angle: angleController.value * pi * 2,
child: child,
);
},
child: GestureDetector(
onTap: () {
angleController.stop();
},
child: Icon(
Icons.forward,
color: Colors.pink,
size: 100.0,
)),
),
],
),
),
);
}
}

You need a timer.periodic:
https://api.flutter.dev/flutter/dart-async/Timer/Timer.periodic.html
Use it to keep the rotation function running and just turn it off when clicked.
var timer = Timer.periodic(Duration(seconds: 5), (timer) {
//Your function goes here
});
// Cancel the timer
timer.cancel();

Related

How do I center align my iFrameElement within HtmlElementView in flutter?

I am using an HtmlElementView in my flutter web project for showing a web image/pdf etc.
I am not able to figure out a way to align the element within the frame. As shown by the below sample code example, if the image size is smaller than parent widget size, it is shown in top left alignment. I have a feeling this has to do with some iframe style setting but not able to figure out.
import 'dart:html';
import 'dart:ui' as ui;
import 'package:flutter/cupertino.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
theme: ThemeData.dark(),
home: Home(),
);
}
}
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Material App Bar'),
),
body: InteractiveViewer(
child: Container(
alignment: Alignment.center,
width: 3000,
height: 3000,
child: EmbedWebView(
src:
'https://picsum.photos/id/1/200/300', //'https://www.youtube.com/embed/3fB1mxOsqJE',
width: 500,
height: 550))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {},
),
);
}
}
class EmbedWebView extends StatefulWidget {
final Key? key;
final String src;
final double height, width;
EmbedWebView(
{this.key, required this.src, required this.height, required this.width});
#override
State<StatefulWidget> createState() {
return EmbedWebViewState();
}
}
class EmbedWebViewState extends State<EmbedWebView>
with AutomaticKeepAliveClientMixin {
#override
void initState() {
super.initState();
final IFrameElement _iframeElement = IFrameElement()
..height = '100%'
..width = '100%'
..src = widget.src
..style.border = 'none'
..style.overflow = "hidden"
..allow = "autoplay"
..allowFullscreen = true;
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
widget.src,
(int viewId) => _iframeElement,
);
}
#override
void dispose() {
super.dispose();
}
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
super.build(context);
return Center(
child: Container(
color: Colors.white,
width: widget.width,
height: widget.height,
child: HtmlElementView(
// key: UniqueKey(),
viewType: widget.src,
),
),
);
}
}
When the above code is run using flutter run -d chrome, this is what I get. It can be seen that the image in not centred.
sample code output
Try wrapping the EmvedWebView with an Expanded. Probably the EmvedWebView is not occupying the whole Container, implying that even if the Container is centered his child is not

Calling a widget with a function as a parameter in Flutter

I am trying to call a custom widget that has a function as a parameter, however I got no clue what parameter I could assign to it. I have tested all the ideas I came up with but with no success. The idea for this, I have gained from a tutorial, however I have done some things differently, as I have different requirements.
This is my code:
import 'package:flutter/material.dart';
class NewTransaction extends StatelessWidget {
final Function addTx;
const NewTransaction({Key? key, required this.addTx}) : super(key: key);
#override
Widget build(BuildContext context) {
return Text('I cant solve this problem');
}
}
========================================================================
import 'package:flutter/material.dart';
import 'package:function_parameter_problem/new_transaction.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
NewTransaction(
addTx:
addTx), // What parameter can/should I pass here? It is crucial for my project
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Edit: Okay, but let's say that the NewTransaction() function returnes a scaffold with appbar, etc and I have to call it again, however in the following scenario:
_wykonajZapytanie() { //function called onPressed in the main window
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NewTransaction()),
); /*I have to put a parameter here, but I just want to display another window, I don't know why, but I just can't get any ideas*/
}
IMPORTANT TO NOTICE In the original project, if it comes to the first example I have provided, I do not call NewTransaction(addTx...) in the main class, but in the UserTransaction class.
tldr I need to assemble an expandable list in the main class - which can be done the way below from what I know, but also I need to call this function in the the main class on the onPressed of a button to display all of the textfields, etc.
import 'package:flutter/material.dart';
import './new_transaction.dart';
import './transaction_list.dart';
import '../models/transaction.dart';
class UserTransaction extends StatefulWidget {
#override
_UserTransactionState createState() => _UserTransactionState();
}
class _UserTransactionState extends State<UserTransaction> {
final List<Transaction> _userTransactions = [
Transaction(
id: 1,
date: DateTime.now(),
numTel: 911911911,
// scoring: 'Link wygasł',
user: 'Polizei pau pau'),
Transaction(
id: 2,
date: DateTime.now(),
numTel: 911911911,
// scoring: 'Link wygasł',
user: 'Tha police')
];
void _addNewTransaction(int txNumTel, /* String txScoring,*/ String txUser) {
final newTx = Transaction(
numTel: txNumTel,
/*scoring: txScoring,*/
user: 'PLZ WORK',
date: DateTime.now(),
id: 3,
);
setState(() {
_userTransactions.add(newTx);
});
}
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
NewTransaction(_addNewTransaction),
]);
}
}
import 'package:flutter/material.dart';
class NewTransaction extends StatelessWidget {
final VoidCallback function;
//if nothing returns
//else typedef CustomFunc = Function(int param); (replace int with your data type)
const NewTransaction({Key? key, required this.function}) : super(key: key);
#override
Widget build(BuildContext context) {
return InkWell(
child: Text('I cant solve this problem'),
onTap:function,
//if custom
//onTap: (){
// function(params);
//}
);
}
}
Call like below...
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
NewTransaction(
function: (){
//todo
},
//if custome function: (params){ todo },
)
],
),
),
If I understood your question correctly, this is the way you can pass a function with parameters:
import 'package:flutter/material.dart';
class NewTransaction extends StatelessWidget {
final Function() addTx;
const NewTransaction({Key? key, required this.addTx}) : super(key: key);
#override
Widget build(BuildContext context) {
return Text('I cant solve this problem');
}
}
When passing this Function, make sure to pass it like this: NewTransaction(addTx: () => addTx());. If you pass it like this: NewTransaction(addTx: addTx()); the function gets called instantly.
When you sayFunction addTx it means any function can be passed.
If Function() addTx it means function with no parameter.
If Function(int) addTx it means function with one required positional parameter integer.
If void Function() addTx it means function with no parameter and return type should be void.
In flutter you can also use
VoidCallback which is basically void Function() written like this
final VoidCallback addTd.
.
or can use ValueChanged<T> which is basically void Function(T value)
More info at:
https://dart.dev/guides/language/language-tour#functions

The following assertion was thrown building Builder: setState() or markNeedsBuild() called during build?

iam new to flutter but really i dont see what is the error in my code it first it keeps showing that :
The following assertion was thrown building Builder:
setState() or markNeedsBuild() called during build.
and when i hot relod this comes up
line 4016 pos 12: '!_debugLocked':
is not true.
i dont know what to do and why this is happening because its the first time
class _RepresentativeUiState extends State<RepresentativeUi> {
int _currentIndex = 0;
// navy bottom pages
final _newsFeedPage = RNewsFeed();
final _profilePage = RProfile();
final _addPostPage = RAddPost();
final _libraryPage = RLibrary();
Widget _showPage = RNewsFeed();
Widget _pageChooser(int page) {
switch (page) {
case 0:
return _newsFeedPage;
break;
case 1:
return _addPostPage;
break;
case 2:
return _libraryPage;
break;
case 3:
return _profilePage;
break;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: CurvedNavigationBar(
index: _currentIndex,
items: <Widget>[
Icon(
FontAwesomeIcons.newspaper,
size: 30,
),
Icon(
FontAwesomeIcons.plus,
size: 30,
),
Icon(
FontAwesomeIcons.book,
size: 30,
),
Icon(
FontAwesomeIcons.user,
size: 30,
),
],
color: Colors.white,
buttonBackgroundColor: Colors.white,
backgroundColor: Color(0xff131535),
animationCurve: Curves.easeIn,
animationDuration: Duration(milliseconds: 400),
onTap: (int tappedIndex) {
setState(() {
_showPage = _pageChooser(tappedIndex);
});
},
),
body: Container(
child: _showPage,
),
);
}
}
class RNewsFeed extends StatefulWidget {
#override
_RNewsFeedState createState() => _RNewsFeedState();
}
class _RNewsFeedState extends State<RNewsFeed> {
#override
Widget build(BuildContext context) {
return Container(
child: Text('1'),
);
}
}
class RAddPost extends StatefulWidget {
#override
_RAddPostState createState() => _RAddPostState();
}
class _RAddPostState extends State<RAddPost> {
#override
Widget build(BuildContext context) {
return Container(
child: Text('2'),
);
}
}
class RLibrary extends StatefulWidget {
#override
_RLibraryState createState() => _RLibraryState();
}
class _RLibraryState extends State<RLibrary> {
#override
Widget build(BuildContext context) {
return Container(
child: Text('3'),
);
}
}
class RProfile extends StatefulWidget {
#override
_RProfileState createState() => _RProfileState();
}
class _RProfileState extends State<RProfile> {
String _name ;
#override
void initState() {
super.initState();
SharedPreferences.getInstance().then((value) => {
setState((){
value.getString('name');
})
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff131535),
body: SingleChildScrollView(
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
radius: 50,
),
Text(
'$_name',
style: TextStyle(color: Colors.black),
),
],
),
),
),
);
}
}
This is the culprit i believe:
SharedPreferences.getInstance().then((value) => {
setState((){
value.getString('name');
})
});
There's no need to ever call setState() in initState(). So what happens now is that while the page is building, setState() is trying to initiate another build process. Simply remote the setState wrapper around value.getString('name');.

Flutter: dynamically add tabs and keep state with AutomaticKeepAliveClientMixin

I'm trying to create a form with tabs. In each tab I have TextFormField. Tabs have AutomaticKeepAliveClientMixin to keep their State. Tabs can be created dynamically. When new tab is created, it is inserted in the middle of the tabs list.
Problem: when new tab is inserted, its TextFormField keep state of the next tab and so on. It seems states keeps in order from 1 to n. Is there any way to keep the right state for tabs?
Thanks in advance.
import 'package:flutter/material.dart';
class TabTesting extends StatefulWidget {
#override
_TabTestingState createState() => _TabTestingState();
}
class _TabTestingState extends State<TabTesting> with TickerProviderStateMixin {
List<MyTab> _tabs = [
MyTab(TabData("1", "1")),
MyTab(TabData("3", "3")),
];
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = new TabController(vsync: this, length: _tabs.length);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("TabTesting"),
bottom: TabBar(
controller: _tabController,
labelPadding: EdgeInsets.symmetric(vertical: 16.0),
tabs: _tabs.map((tab) => Text(tab.tabData.name)).toList(),
),
),
body: Container(
padding: EdgeInsets.all(32.0),
child: TabBarView(
controller: _tabController,
children: _tabs,
),
),
persistentFooterButtons: <Widget>[
RaisedButton(
child: Text("Add tab"),
onPressed: () {
final newTab = MyTab(TabData("2", "2"));
final newTabs = _tabs;
newTabs.insert(1, newTab);
final index = _tabController.index;
setState(() {
_tabs = newTabs;
_tabController = TabController(
vsync: this,
length: newTabs.length,
initialIndex: index);
});
},
),
],
);
}
}
class MyTab extends StatefulWidget {
final tabData;
MyTab(this.tabData);
#override
_MyTabState createState() => _MyTabState();
}
class _MyTabState extends State<MyTab> with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
return Tab(
child: TextFormField(
decoration: InputDecoration(labelText: widget.tabData.name),
initialValue: widget.tabData.data,
),
);
}
}
class TabData {
String name;
String data;
TabData(this.name, this.data);
}
You forgot to add super.build(context); as the documentation of AutomaticKeepAliveClientMixin suggests.
#override
Widget build(BuildContext context) {
super.build(context);
return Tab(
child: TextFormField(
decoration: InputDecoration(labelText: widget.tabData.name),
initialValue: widget.tabData.data,
),
);
}

Call widget's own function outside it

I have this a stateful widget which could be in two situations, the first one is a Container with a first text in it, for example, "Register", the second one is a different colored container with a different text, for example "confirm". The Problem is that the transition between these two situations is done using an animation and it's not an on-the-fly logic for example:
color: isSituation1 ? Colors.blue : Colors.red.
it's actually something like this:
color: Color.lerp(Colors.blue, Colors.red, _animation1.value)
and I have a function which runs when the user taps on the container which forwards the animation controller, like so:
_controller1.forward()
and this is a widget called let's say Button1
So in My HomePage stateful widget I have another button which should trigger the inverse process in the Button1 widget, so it would be:
_controller1.reverse()
I tried creating a function in the Button1 widget but then I cannot run it from outside. How could I do it if it's possible?
So basically you want to call methods of your CustomWidget from another widget. You can define ControllerClass that you will emit an instance when you create a new instance of your CustomWidget. This ControllerClass instance will hold the functions of your CustomWidget and you will be able to call them from outside.
By example a class that is a modal rounded progressbar that can be showed and hided from outise with a controller class. In this example a controller class is called ProgressBarHandler. I don't know if it is a better and the right approach but works.
class ModalRoundedProgressBar extends StatefulWidget {
final String _textMessage;
final double _opacity;
final Color _color;
final Function _handlerCallback;
ModalRoundedProgressBar({
#required Function handleCallback(ProgressBarHandler handler), //callback to get a controller
String message = "",
double opacity = 0.7,
Color color = Colors.black54,
}) : _textMessage = message,
_opacity = opacity,
_color = color,
_handlerCallback = handleCallback;
#override
State createState() => _ModalRoundedProgressBarState();
}
class _ModalRoundedProgressBarState extends State<ModalRoundedProgressBar> {
bool _isShowing = false;
#override
void initState() {
super.initState();
// init controller.
ProgressBarHandler handler = ProgressBarHandler();
handler.show = this.show;
handler.dismiss = this.dismiss;
widget._handlerCallback(handler); // callback call.
}
#override
Widget build(BuildContext context) {
if (!_isShowing) return Stack();
return Material(
color: Colors.transparent,
child: Stack(
children: <Widget>[
Opacity(
opacity: widget._opacity,
child: ModalBarrier(
dismissible: false,
color: Colors.black54,
),
),
Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Text(widget._textMessage),
],
),
),
],
),
);
}
void show() {
setState(() => _isShowing = true);
}
void dismiss() {
setState(() => _isShowing = false);
}
}
class ProgressBarHandler {
Function show; // will point to widget show method
Function dismiss; // will point to another method.
}
// ...in another external widget you can do...
// ... code your things and:
var controller;
var progressBar = ModalRoundedProgressBar(
handleCallback: ((handler){ controller = handler; } ),);
//calling show method with controller
RaisedButton(
onPressed: () { controller.show(); }
);
//calling dismiss method with controller
RaisedButton(
onPressed: () { controller.dismiss(); }
);
It is possible, but you probably don't want to do that. You should either provide the AnimationController from the parent or structure your app to prevent such behaviors. Anyway, if you still want to go this way, here you have it.
class HomePage extends StatefulWidget {
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
VoidCallback _reverseAnimation;
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Reverse animation'),
onPressed: () => _reverseAnimation(),
),
Button1((controller) => _reverseAnimation = controller),
],
),
);
}
}
class Button1 extends StatefulWidget {
final ValueChanged<VoidCallback> callback;
Button1(this.callback);
_Button1State createState() => _Button1State();
}
class _Button1State extends State<Button1> with SingleTickerProviderStateMixin {
AnimationController _someAnimationController;
void _reverseAnimation() {
_someAnimationController?.reverse();
}
#override
void initState() {
super.initState();
if (widget.callback != null) {
widget.callback(_reverseAnimation);
}
}
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Start animation'),
onPressed: () => _someAnimationController.forward(),
),
);
}
}