Is There A Way to Either Return 2 values for the property floatingActionButton or to call a setState Whenever a variable Changes? - flutter

I'm new to flutter,
So I'm working on a Flutter app & I Have My Functions & Widget File named: 'Function' Separated from my Main but I'm trying to set state in 'Main' from 'Function'
I have tried to set a global variable inside a MyText class Widget inside 'Function' and import 'Main'==> Function & Vice Versa at the same time, but I can't seem to manipulate the GlobalKey variable which would trigger setState again
(Class & MyText class Has since been Scrapped)
I also tried to set the function from my other file to the button like so
floatingActionButton: functions.random()
And somehow was able to set state (Sorry I Forgot How), but it kept running without being pressed
'Main.dart' Sample Code
String display = "";
class _MyHomePageState extends State<MyHomePage> {
var currentScreen = display;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AutoSizeText(
currentScreen,
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: functions.menu(),
);
} //Build
}// _MyHomePageState
'Function.dart' Sample Code
SpeedDial menu(){
return SpeedDial(
SpeedDialChild(
child: Icon(Icons.autorenew),
backgroundColor: Colors.lightBlueAccent,
label: 'New Activity',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () => random(),
),
)
random(){
...
return someString;
}
Intended Result
When Child 'New Activity' is clicked, setState is called with the variable currentScreen's state being set to the result from the function 'random()'
Thank You In Advance!

I don't know if this can finish your problem, but the approach will be a little different from your approach because I'm not really familiar with the globalsetkey works...
so from my perspective I'm using the bloc pattern so hope this can give you some inspiration how to resolve this problems
in classBLoc.dart
BehaviorSubject<bool> _dialClicked = BehaviorSubject<bool>();
Observable<bool> get dialClicked => _dialClicked.stream;
Function(bool) get dialClickedListener => _dialClicked.sink.add;
in main.dart
section floatingActionButton,
floatingActionButton: functions.menu(currentScreen),
in Function.dart
Widget menu(){
final bloc = Provider.of<classBLoc>();
return StreamBuilder(stream: bloc.dialClicked, initialData: false,builder: (context, snapshot){
return SpeedDial(
SpeedDialChild(
child: Icon(Icons.autorenew),
backgroundColor: Colors.lightBlueAccent,
label: 'New Activity',
labelStyle: TextStyle(fontSize: 18.0),
onTap: () => snapshot.data ? currentScreen : random(), // this used for checking data if have already been clicked or not
);
}),
);
Hope this can you some inspiration how it's worked //sorry if there is wrong bracketed

Related

Conditionally render widgets based on key/value pair Flutter

I am trying to conditionally render widgets based on a state value in MyApp. My idea was the state value would be an integer (1-3). I would have a Map at the top of my project that looks like this:
Map _widgetType = {
1: WidgetOne(),
2: WidgetTwo(),
3: WidgetThree()
};
And then I have a state value called _type that is initialized at 1. I have a function that updates this value based on a selection from a list of options.
void _toggleClipped(int type) {
setState(() {
_type = type;
});
}
The build looks like the below.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Text(
"Hi! I'm Matt!",
style: TextStyle(fontSize: 25),
),
_widgetType[_type],
Text(
"Click the button below to clip image!",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25))
],
),
),
);
}
The _widgetType[_type] would be the associated widget being rendered based upon the value for _type.
Is this doable in Flutter? I am getting an error saying The values in a const list literal must be constants. Try removing the keyword 'const' from the list literal.

Flutter Semantics Reads button title on both single tap and double tap

I have a tooltip in my UI which has semantics label "Tooltip to know about your number". Below is the code snippet for the same.
Semantics(
label: 'Tooltip to know about your number',
child: InkWell(
child: Image.asset('images/info_selected.png'),
onTap: (){
//some action top show tooltip
},
),
),
When accessibility is ON , and I single tap on info Inkwell, it announce "Tooltip to know about your number" as expected. But my issue here , Its also announcing the same when I double tap.. It should only do the functionality which I wrote inside onTap function when I double tap. What is the best way to make it like , it should not announce when I double tap?
Same code is working fine in android and it announce only when I single tap.. only iOS screen reader is announcing the label on both single tap and double tap..
Same issue when I use Gesture Detector or Button instead of InkWell..
Inkwell have a onTap and onDoubleTap both functions available
Reference - https://api.flutter.dev/flutter/material/InkWell-class.html
Output :-
Code :-
import 'package:flutter/material.dart';
class InkwellExample extends StatefulWidget {
const InkwellExample({Key? key}) : super(key: key);
#override
State<InkwellExample> createState() => _InkwellExampleState();
}
class _InkwellExampleState extends State<InkwellExample> {
String taps = "";
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Scaffold(
body: SizedBox(
width: size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
InkWell(
child: const Icon(Icons.info),
onTap: () => setState(() {
taps = "TAP";
}),
onDoubleTap: () => setState(() {
taps = "Double TAP";
}),
),
Text(
taps == "" ? "" : taps,
style: const TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
);
}
}
To keep screen readers from reading anything other than what you have in your label parameter, add excludeSemantics: true. So your code would look like this:
Semantics(
label: 'Tooltip to know about your number',
excludeSemantics: true,
child: InkWell(
child: Image.asset('images/info_selected.png'),
onTap: (){
//some action top show tooltip
},
),
),
Another parameter which may be of interest is onTapHint.
One reference I've used:
https://www.woolha.com/tutorials/flutter-using-semantics-mergesemantics-examples

How to display a Cubit state modified in a Widget into another Widget?

Im developing a Shopping cart using the BLoC pattern and I got stuck trying to learn the subset Cubit. My main question is how can I display the state of a previously updated Cubit? My flow is the next...
On the Product Screen I increase/decrease the items I want to use.
To push to change the state, I click a button and send the items as a parameter to the Cubit function.
The item list gets updated and I want to get it into another widget that is outside of the Product Screen.
Here is the code:
main.dart
void main() {HttpOverrides.global = new MyHttpOverrides();
runApp(
RepositoryProvider<AuthenticationService>(
create: (context) {
return AuthService();
},
child: MultiBlocProvider(
providers: [
BlocProvider<AuthenticationBloc>(
create: (context) {
final authService = RepositoryProvider.of<AuthenticationService>(context);
return AuthenticationBloc(authService)..add(AppLoaded());
}
),
BlocProvider<CartCubit>(create: (context) => CartCubit())
],
child: MyApp(),
),
)
);
}
product_screen.dart
BlocBuilder<CartCubit, List<Item>>(
builder: (context, state) {
return Row(
children: [
_shoppingItem(0),
SizedBox(
width: SizeConfig.blockSizeHorizontal * 2,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
color: Color(0xFF48AD71),
),
child: IconButton(
onPressed: () {
for (int i = 1; i <= counter; i++) {
items.add(widget.item);
print('something');
}
context.read<CartCubit>().addToList(items);
},
icon: Icon(
Icons.shopping_bag),
color: Colors.white,
),
),
],
);
},
)
cart_cubit.dart
class CartCubit extends Cubit<List<Item>> {
CartCubit() : super([]);
void addToList(List<Item> items) {
state.addAll(items);
emit(state);
print(state);
}
}
What I should add on my Cart Screen so I can get the value of the Cubit State? Also, do this should be better handled by using a bloc instead of cubit?
Edit: Based on the comment of Loren.A I removed the BlocBuilder of my ProductScreen and I added it to my CartScreen.
class _CartScreenState extends State<CartScreen> {
#override
Widget build(BuildContext context) {
SizeConfig().init(context);
return SingleChildScrollView(
child: BlocBuilder<CartCubit, List<Item>>(
builder: (context, state) {
return Column()
...
...
Align(
alignment: Alignment.topRight,
child: Text(
state.length.toString(), // this is not updating
textAlign: TextAlign.end,
style: TextStyle(
fontFamily: 'SinkinSans',
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: Color(0xFFC9C9C9)),
),
),
Cubit is fine for this. You can update widgets anywhere in your app based on that list just by adding another BlocBuilder<CartCubit, List<Item>>. So just add another one to your Cart page and do what ya gotta do inside of it. It will reflect the previous changes.
Edit: Just noticed that it doesn't appear that you're actually rebuilding any widgets in your product screen so that BlocBuilder you have is not really doing anything. You can remove that and just use it where you need to reflect that value of the list. You can still fire that addToList method without being inside a BlocBuilder.

Flutter: Very basic stupid beginner question

I am trying to learn Flutter and so I am following a YouTube tutorial.
Now I have a question I can't really describe, it is working but i don't understand why.
My Program contains two .dart files, you can see them below.
Is the the Question Class in questions.dart executed by pressing Button 1 or 3 (Answer 1, Answer 3)?
If I understand that correctly the buttons will execute "onPressed: _answerQuestions,". But _answerQuestions only changes the State of "questionIndex" and is not calling something else, right? The UI gets rebuild and the Question Text changes.
But Questions Class does change the appearence of the text with the "style", this is its only task right now?
So why do we have a second dart File for that? We could simply change the style within the main.dart?
main.dart:
import 'package:flutter/material.dart';
import './question.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
var questionIndex = 0;
void _answerQuestions() {
setState(() {
questionIndex = questionIndex + 1;
});
print(questionIndex);
}
#override
Widget build(BuildContext context) {
var questions = [
'What\'s your favorite color?',
'What\'s your favorite animal?',
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My First App'),
),
body: Column(
children: [
Question(questions[questionIndex]),
RaisedButton(
child: Text('Answer 1'),
onPressed: _answerQuestions,
),
RaisedButton(
child: Text('Answer 2'),
onPressed: () => print('Answer 2 chosen')),
RaisedButton(
child: Text('Answer 3'),
onPressed: _answerQuestions,
),
],
),
),
);
}
}
And question.dart:
import 'package:flutter/material.dart';
class Question extends StatelessWidget {
final String questionText;
Question(this.questionText);
#override
Widget build(BuildContext context) {
return Text(
questionText,
style: TextStyle(fontSize: 28),
);
}
}
Is the the Question Class in questions.dart executed by pressing
Button 1 or 3 (Answer 1, Answer 3)?
Both. Question is a StatlessWidget holding your question.
When you press any of the buttons(1 & 2) MyAppState gets rebuilt with a new question index and because you pass the question text to the Question Widget using that index, Question(questions[questionIndex]), Question will get a new value and show it, because you called setState, if you had not, behind the scenes it would still change the value but because the widget wouldn't be rebuilt, the visual side would stay the same.
The why you have two separate files? It makes it easier to see what your app is doing, especially for bigger projects. Usually, one file should have one purpose, do not mix functionalities in one file or you'll get a messy code really fast.
In this case, the equivalent for not having the question in a separate file would be:
body: Column(
children: [
// from
// Question(questions[questionIndex]),
// to
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
RaisedButton(
child: Text('Answer 1'),
onPressed: _answerQuestions,
),
RaisedButton(
child: Text('Answer 2'),
onPressed: () => print('Answer 2 chosen')),
RaisedButton(
child: Text('Answer 3'),
onPressed: _answerQuestions,
),
],
),
But what if you need to use that same question in several places?
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
You'll have to write that same code every time you need it, and this is a really simple one, imagine you have a widget with much more code, do you really want to write it all over again every time you need it?
No, you just create a new widget thas has the functionality you need and call it whenever you need it.
Question(questions[questionIndex]),
Question(questions[questionIndex]),
Question(questions[questionIndex]),
Question(questions[questionIndex]),
When i code in flutter, i usually tend to start a file for every new "screen" in the app.
Also, i create one file for I/O (api connections, DB...), and a file for common functions.
It is good to have several files because the moment you want to build a big app you will realise how long it is. My last app was around 10k lines of code. Impossible to mantain with only 1 file.
Also, dividing by file is useful for code reutilisation.
GL
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
var questionIndex = 0;
void _answerQuestions() {
setState(() {
questionIndex = questionIndex + 1;
});
print(questionIndex);
}
#override
Widget build(BuildContext context) {
var questions = [
'What\'s your favorite color?',
'What\'s your favorite animal?',
];
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('My First App'),
),
body: Column(
children: [
Text(
questions[questionIndex],
style: TextStyle(fontSize: 28),
),
RaisedButton(
child: Text('Answer 1'),
onPressed: _answerQuestions,
),
RaisedButton(
child: Text('Answer 2'),
onPressed: () => print('Answer 2 chosen')),
RaisedButton(
child: Text('Answer 3'),
onPressed: _answerQuestions,
),
],
),
),
);
}
}
It can be done.. As #Michael Said you'll get a messy code really fast. You should follow BEST PRACTICES While Learning a Language. It is equally IMPORTANT. Will help you in long RUN.

How to update a custom Stateful Widget using Floating Action Button

I've recently started using Flutter just for fun, and I'm stuck on adding actual functionality to the code without having everything inside one class.
Essentially, I'm trying to use a FloatingActionButton to increment the value of a Text Widget which stores the value of the user's level as an integer, but I don't want to have the whole app as a StatefulWidget because only the level is going to be updated. When the button is pressed, the value should increment by 1 and then show the new value on the screen.
I have the Level Text Widget inside a StatefulWidget class along with a function to update the level by one and set the state; the MaterialApp inside a StatelessWidget class; and the main body code inside another StatelessWidget class.
If this isn't the best way to do it please do let me know so I can improve for future projects, thanks.
main.dart
import 'package:flutter/material.dart';
main() => runApp(Start());
/// The Material App
class Start extends StatelessWidget{
#override
Widget build(BuildContext context){
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.grey[800],
appBar: AppBar(
title: Text("Home Page"),
backgroundColor: Colors.cyan,
centerTitle: true,
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: Colors.orange,
child: Icon(Icons.add, color: Colors.black,),
),
body: HomePage(),
),
);
}
}
/// Main Content for the page (body)
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// removed other children so there's less code to scan through for you :)
Padding(
padding: EdgeInsets.fromLTRB(30, 0, 0, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// Text that just says "Level"
Text(
"Level",
style: TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
fontSize: 32,
),
),
// space between text and actual level value
SizedBox(height: 10),
// Create new level widget
Level(),
],
),
),
],
),
);
}
}
/// Updating level using a Stateful Widget
class Level extends StatefulWidget{
#override
State<StatefulWidget> createState(){
return _LevelState();
}
}
class _LevelState extends State<Level>{
int level = 0;
void incrementLevel(){
setState(() {
level += 1;
});
}
#override
Widget build(BuildContext context){
return Text(
"$level",
style: TextStyle(
color: Colors.grey[900],
fontWeight: FontWeight.normal,
fontSize: 28,
),
);
}
}
It actually is a weird way of doing it. However, there is various ways of achieving this
To give an example:
You can use KEYs to remotely redraw the child state
If you want an advanced solution that can assist you in bigger projects. You can use state management tecniques. You can find a lot of tutorials in the internet but these are some of them. BLOC, Provider, InheritedWidget.
Basicaly all of them does the same thing. Lifts up the state data so the place of the redrawn widget on the widget tree will not be important.
I strongly encourage you to watch some tutorials starting with the Provider. I hope this helps