I have a function start timer that requires a stateful widget and I need it to be called in another Class which is also a stateful widget class, I have tried making an object of the class PhoneAuthState phone = PhoneAuthState() and taping it into the function but the timer wouldn't start counting down after pressing the send button,
Here is the first class
`class PhoneAuth extends StatefulWidget {
const PhoneAuth({Key? key}) : super(key: key);
#override
State<PhoneAuth> createState() => PhoneAuthState();
}
class PhoneAuthState extends State<PhoneAuth> {
int start = 30;
#override
Widget build(BuildContext context) {
return Scaffold(
ReusableTField(),
RichText(
text: TextSpan(children: [
TextSpan(
text: "Send OTP again in",
style: TextStyle(color: Colors.orange, fontSize: 17),
),
TextSpan(
text: " 00:$start",
style: TextStyle(color: Colors.redAccent, fontSize: 17),
),
TextSpan(
text: "sec",
style: TextStyle(color: Colors.orange, fontSize: 17),
),
]),
),
**Here is the function below**
void startTimer() {
const onsec = Duration(seconds: 1);
Timer timer = Timer.periodic(onsec, (timer) {
if (start == 0) {
setState(() {
timer.cancel();
});
} else {
setState(() {
start--;
});
}
});
`
Then this is the class(in another file) that needs the function to start counting down when the send button is tapped nothing happens on the emulator, even after the startTimer contains setState
class ReusableTField extends StatefulWidget {
#override
State<ReusableTField> createState() => _ReusableTFieldState();
}
class _ReusableTFieldState extends State<ReusableTField> {
#override
Widget build(BuildContext context) {
return Container(
suffixIcon: InkWell(
onTap: () {} // Here is where I called the function with PhoneAuthState phone =
// PhoneAuthState()... phone.startTimer() but the code does not work,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 14),
child: Text(),
),
)
if you want to use the same code on multiple classes define a static class and write this method as a static method and call it from anywhere.
I think you function is at wrong place keep it out of build method and then call.
Related
I created a widget and I want to pass a function to this widget, but when I try to do this I get this error.
Moreover when this function is passed to a widget it is automatically used, because it debugPrint "MONEY CHANGED".
This is the function code:
class Functions {
changeMoney(int money) {
Boxes.getCharacter().get(0)!.money =
Boxes.getCharacter().get(0)!.money + money;
debugPrint("MONEY CHANGED");
}
}
And this is widget's code:
class DialogButton extends StatefulWidget {
const DialogButton(
{Key? key,
required this.answer,
required this.function,
required this.possible})
: super(key: key);
final String answer;
final Function function;
final bool possible;
#override
State<DialogButton> createState() => _DialogButtonState();
}
class _DialogButtonState extends State<DialogButton> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: ElevatedButton(
onPressed: () => {
Navigator.of(context, rootNavigator: true).pop(),
widget.function
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 18.0),
child: Row(children: [
Expanded(child: Container()),
Text(
widget.answer,
style: rajdhaniStyle(weight: FontWeight.w600, size: 18),
),
Expanded(child: Container()),
]),
)),
);
}
}
So the question is how should i correctly pass a function inside widget without automatically make it turn on the function and without getting an error?
If the function have parameter, then the received widget (here is DialogButton) also need to declare parameter type. Example, the function is: void doSomething(String hehe, int yolo) {}. Then your DialogButton should be declare as Function(String, int) onTap.
More details, in first screen, you can call DialogButton like this:
class Screen1 extends StatelessWidget {
#override
build(...) {
// do something
DialogButton(
answer: "your answer",
function: (double money) {},
possible: true,
)
}
}
Otherwise, if you want to split/separate the function (not write-in-line like above), you could do as follow:
class Screen1 extends StatelessWidget {
#override
build(...) {
// do something
DialogButton(
answer: "your answer",
function: myFunction,
possible: true,
)
}
myFunction(double money) {}
}
I have a stateful widget that returns a scaffold as follows:
class TimerPage extends StatefulWidget {
const TimerPage({Key? key, required this.title}) : super(key: key);
final String title;
#override
TimerPageState createState() => TimerPageState();
}
class TimerPageState extends State<TimerPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
mainAxisAlignment: MainAxisAlignment.center,
children: [
getMaterialTextButton('1', 'Roboto', 24, keypadPressed('1')), /// ERROR
getMaterialTextButton('2', 'Roboto', 24, keypadPressed2('2')), /// ERROR
]
),
);
}
}
So what I'm trying to do is pass a generic function inside getMaterialTextButton() that will return a material button as follows:
// this function is within the TimerPageState class
Widget getMaterialTextButton(String text, String fontname, double fontsize, Function onPressAction) {
return (
MaterialButton(
onPressed: () {
onPressAction(text);
},
color: Colors.blue,
textColor: Colors.white,
child: Text(
text,
style: TextStyle(fontFamily: fontname, fontSize: fontsize)
),
padding: const EdgeInsets.all(24),
shape: const CircleBorder(),
)
);
}
// this function is to be called when the button 1 is pressed
// also resides inside TimerPageState class
void keyPressed (String text) {
print('Pressed: $text');
}
// this function is also to be called when button 2 is pressed
// also resides inside TimerPageState class
void keyPressed2 (String text) {
print('Pressed: $text');
}
But this doesn't seem to work as dart is giving me an exception:
Exception has occurred. _TypeError (type 'Null' is not a subtype of type 'Function')
. How can I do this operation properly?
Firstly you should prefer a full signature in your function type annotations https://dart.dev/guides/language/effective-dart/design#prefer-signatures-in-function-type-annotations
so
Widget getMaterialTextButton(String text, String fontname, double fontsize, Function onPressAction) {...}
should be
Widget getMaterialTextButton(String text, String fontname, double fontsize, void Function(String) onPressAction) {...}
Secondly, this is not passing in a function:
getMaterialTextButton('1', 'Roboto', 24, keypadPressed('1')),
That is calling the keypadPressed and passing in the result of the function, which appears to be void. Remove the parenthesis, and do not pass anything into keypadPressed, the body of getMaterialTextButton is where the function should be called.
getMaterialTextButton('1', 'Roboto', 24, keypadPressed),
you are passing the return value of the function, not the function itself
change this
getMaterialTextButton('1', 'Roboto', 24, keypadPressed('1')),
to this
getMaterialTextButton('1', 'Roboto', 24, keypadPressed),
I have a word: money. I want to show every letter from that word after 2 seconds delay: First show letter m, after 2 seconds on screen should be visible: m-o, after next two seconds: m-o-n etc. I am thinking about save every letter to array: [m-, o-,n-,e-,y] and after that using Timer add Text.
Things which I don't know how achieve: how can I split this word to this array? And How add/show Text using Timer.
Let's follow your approach and make it happen.
To make an array from word, use split("") and it will return a list of string.
Like this
List<String> _totalChar = "money".split("");
Result
Full Widget
If you want to play it on start, put _textAnimationSetUp() inside initState(). BTW, I'm not focusing on button state. Let me know if you face any trouble with this widget.
import 'dart:async';
import 'package:flutter/material.dart';
class AnimatedText extends StatefulWidget {
AnimatedText({Key? key}) : super(key: key);
#override
_AnimatedTextState createState() => _AnimatedTextState();
}
class _AnimatedTextState extends State<AnimatedText> {
Timer? timer;
String buttonText = "play";
///* let's make list from word
List<String> _totalChar = "money".split("");
List<String> _visibleChar = [];
int currentIndex = 0;
_textAnimationSetUp() async {
timer = Timer.periodic(Duration(seconds: 2), (timer) {
setState(() {
if (currentIndex < _totalChar.length)
_visibleChar.add(
"${currentIndex > 0 ? "-" : ""}${_totalChar[currentIndex++]}");
else
timer.cancel();
});
});
}
get _textStyle => TextStyle(
fontSize: 40,
);
#override
void dispose() {
if (timer != null && timer!.isActive) timer!.cancel();
super.dispose();
}
_play() async {
setState(() {
currentIndex = 0;
_visibleChar.clear();
buttonText = "restart";
});
if (timer != null && timer!.isActive) timer!.cancel();
_textAnimationSetUp();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
//* removing everything except letter and -
_visibleChar
.toString()
.replaceAll(" ", "")
.replaceAll(",", '')
.replaceAll("[", '')
.replaceAll("]", ""),
style: _textStyle,
),
ElevatedButton(
onPressed: () {
_play();
setState(() {});
},
child: Text(buttonText),
),
],
),
),
);
}
}
Install :
dependencies:
animated_text: ^1.0.2
Then :
import 'package:animated_text/animated_text.dart';
import 'package:flutter/material.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> {
bool play = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animated Text'),
),
body: Container(
color: Colors.white,
child: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: 300,
child: AnimatedText(
alignment: Alignment.center,
speed: Duration(milliseconds: 1000),
controller: AnimatedTextController.loop,
displayTime: Duration(milliseconds: 1000),
wordList: ['animations.', 'are.', 'easier.', 'now.'],
textStyle: TextStyle(
color: Colors.black,
fontSize: 55,
fontWeight: FontWeight.w700),
),
),
],
),
),
);
}
}
You can use Future delay for every letter. Something like this:
timer() async {
await Future.delayed(Duration(milliseconds: 200));
setState(() {
letterVisible = true;
});
}
I want the Textfield and the fontFamily in the picture at the top to change when the ElevatedButton is pressed. What should I do? I want to try GetX.
home_page.dart
ListView(
scrollDirection: Axis.horizontal,
children: [
FontFamilyWidget(
fontFamily: 'Cafe24SsurroundAir',
buttonName: '✈️ 카페24 써라운드 에어'),
const SizedBox(width: 5),
FontFamilyWidget(
fontFamily: 'RIDIBatang', buttonName: '📚 리디바탕'),
const SizedBox(width: 5),
FontFamilyWidget(
fontFamily: 'InkLipquid', buttonName: ' 잉크립퀴드체'),
const SizedBox(width: 5),
.
.
.
fontfamily_widget.dart
part of 'font_controller.dart'
String select = 'RIDIBatang';
void onClickChangeFont(String changedFontFamily) {
select = changedFontFamily;
update();
}
part of 'fontfamily_widget.dart'
class FontFamilyWidget extends StatefulWidget {
final String fontFamily;
final String buttonName;
final String changedFontFamily;
const FontFamilyWidget({
Key? key,
required this.fontFamily,
required this.buttonName,
required this.changedFontFamily,
}) : super(key: key);
#override
_FontFamilyWidgetState createState() => _FontFamilyWidgetState();
}
class _FontFamilyWidgetState extends State<FontFamilyWidget> {
FontController c = Get.find();
#override
Widget build(BuildContext context) {
return ElevatedButton(
//텍스트필드와 상단 텍스트의 fontfamily를 변경해주는 함수
onPressed: () {
c.onClickChangeFont(widget.changedFontFamily);
},
child: Text(
widget.buttonName,
style: TextStyle(fontFamily: widget.fontFamily),
),
);
}
}
After that, FontFamilyWidget was applied to home_page.dart.
I am totally flutter beginner.
What I want to do is pass the data (by TextController) from StatefulWidget to another one.
Here is my code (passive Widget)
import 'package:flutter/material.dart';
class VocabularyText extends StatefulWidget {
final String text;
// ignore: sort_constructors_first
const VocabularyText ({ Key key, this.text }): super(key: key);
#override
_VocabularyTextState createState() => _VocabularyTextState();
}
class _VocabularyTextState extends State<VocabularyText> {
Offset offset = Offset.zero;
#override
Widget build(BuildContext context) {
return Container(
child: Positioned(
left: offset.dx,
top: offset.dy,
child: GestureDetector(
onPanUpdate: (details) {
setState(() {
offset = Offset(
offset.dx + details.delta.dx, offset.dy + details.delta.dy);
});
},
child: const SizedBox(
width: 300,
height: 300,
child: Padding(
padding: EdgeInsets.all(8),
child: Center(
child: Text(
'a',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 28,
color: Colors.red
)
),
),
),
)),
),
);
}
}
The thing is here
child: Text(
//
widget.text,
//
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 28,
color: Colors.red
)
),
According to my research, this should work, but it doesn't. Why did I make a mistake?
Here is references
How to add a draggable "textfield" to add text over images in flutter?
Passing Data to a Stateful Widget
Thank you in advance.
edit
i answered before seeing the image it wasn't there
after seeing the image
what causing the problem is this
widget.text
the correct way to use it in Text widget is like this
Text('${widget.text}'),
i would suggest that you do the following
to send data to Statefull Widget first you use Navigator or any other method to open this widget to the user like so
return GestureDetector(
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
//note here between the () you pass the variable
Categories(companies[index].id, companies[index].name)),
)},
and then to receive them you do like this in my case its Categories Class
class Categories extends StatefulWidget {
//getting company id from home page
final int companyId;
final companyName;
Categories(this.companyId , this.companyName);
#override
_CategoriesState createState() => _CategoriesState();
}
class _CategoriesState extends State<Categories> {
#override
Widget build(BuildContext context) {
...... rest of the code
and now to use the data you can do like this for example
widget.companyId
this was an example from my code now lets jump to your code
to receive the text from the text editing controller you do
class TextReceiver extends StatefulWidget {
//getting company id from home page
final String userInput;
TextReceiver(this.userInput);
#override
TextReceiver createState() => _TextReceiver();
}
//to use it
widget.userInput
now to send it you send it through Material Navigator
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => TextReceiver(TextEditingController.text)),
)},
note that you should pass it as TextEditingController.text because the constructor in TextReceiver is specifying the type to String if you passed TextEditingController then the type wouldn't be String it will be TextEditingController type
all of this code is for example and it would't be like your code but it will give you the idea
refer to official docs https://flutter.dev/docs/cookbook/navigation/passing-data
Edit : remove const from this line
child: const SizedBox(
rest of the code
)
to this
child: SizedBox(
rest of the code
)