How to change variable with getx? - flutter

As in the codes I mentioned below, my question is actually simple, but I couldn't find a simple answer on the internet. All the sources I found are going through the same example. There is no simple explanation, but there is good stackoverflow. Let me ask my question without further ado.
I can specify a variable in getx and print that variable on other pages. What I want to do now is I want to change the getx variable in the main file, how can I do that?
I'm posting the wrong version of the code I want to do below for you to understand.
code in getx folder
class numcontroller extends GetxController {
var derece = 20.obs;
}
code is second page
numcontroller deneme = Get.put(numcontroller());
Container(
margin: const EdgeInsets.fromLTRB(27, 10, 0, 0),
child: Row(
children: [
Container(
margin: const EdgeInsets.fromLTRB(5, 0, 0, 0),
child: Text('${deneme.derece.value}',
style: const TextStyle(
fontSize: 45,
fontFamily: 'YesevaOne',
color: Color(0xFF2d4b70)),
),
),
The code I want to run in main.dart
derece = 20
or
derece = 30
When I change the degree manually on main.dart, I want it to change on the second page as well.
EDİTİNG
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:teemapp4/Controller/switch_controller.dart';
import 'routes/app_pages.dart';
import 'routes/app_routes.dart';
import 'themes/app_theme.dart';
//0xFF2d4b70
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: AppRoutes.DASHBOARD,
getPages: AppPages.list,
debugShowCheckedModeBanner: false,
theme: AppTheme.light,
darkTheme: AppTheme.dark,
themeMode: ThemeMode.system,
);
}
}
this is my main.dart code but i am using a bottombar i made with getx. I'm looking for how to change the data in that file through this code.

I don't think So you need to update your main.dart file.
You can add a button on your first page to update values like:
firstPage.dart
class FirstPage extends StatelessWidget {
FirstPage({Key? key}) : super(key: key);
NumController numController = Get.put(NumController());
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
numController.updateDerece(30);
},
child: Text(
"Update Value",
),
),
ElevatedButton(
onPressed: () {
Get.to(() => SecondPage());
},
child: Text("Go To Second Screen"),
),
],
),
),
);
}
}
secondPage.dart
class SecondPage extends StatelessWidget {
SecondPage({Key? key}) : super(key: key);
NumController numController = Get.find<NumController>();
#override
Widget build(BuildContext context) {
return Container(
child: Text(
numController.derece.toString(),
),
);
}
}
Or You can directly update the value on your second page like:
secondPage.dart
class SecondPage extends StatelessWidget {
SecondPage({Key? key}) : super(key: key);
NumController numController = Get.put(NumController());
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
ElevatedButton(
onPressed: () {
//Any Number You can pass in Function
numController.updateDerece(30);
},
child: Text(
"Update Value",
),
),
Obx(
() => Container(
child: Text(
numController.derece.toString(),
),
),
),
],
),
),
);
}
}
numController.dart
import 'package:get/get.dart';
class NumController extends GetxController {
var _derece = 20.obs;
int get derece => _derece.value;
void updateDerece(int value) {
_derece.value = value;
}
}

Try using this way. And update your derece variable value using updateDerece method.
var _derece = 20.obs;
double get derece => _derece.value;
void updateDerece(double value) {
_derece.value = value;
}
////
Obx(() {
return Container(
margin: const EdgeInsets.fromLTRB(27, 10, 0, 0),
child: Row(
children: [
Container(
margin: const EdgeInsets.fromLTRB(5, 0, 0, 0),
child: Text(
'${deneme.derece}',
style: const TextStyle(
fontSize: 45,
fontFamily: 'YesevaOne',
color: Color(0xFF2d4b70)),
),
),
],
),
);
})

Related

Flutter toggle button using Getx for state management

I'm making a toggle button to switch between the unit system, I need to do it using Getx for state management.
This code works, but its using setState() instead
This is the (simplified) code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_toggle_tab/flutter_toggle_tab.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({this.title});
final String? title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _tabTextIndexSelected = 0;
final _listTextTabToggle = ["km / m", "m / ft"];
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Column(
children:[
FlutterToggleTab(
selectedIndex: _tabTextIndexSelected,
selectedBackgroundColors: const [
Colors.blue,
Colors.blueAccent
],
selectedTextStyle: const TextStyle(
color: Colors.white),
unSelectedTextStyle: const TextStyle(),
labels: _listTextTabToggle,
selectedLabelIndex: (index) {
setState(() {
_tabTextIndexSelected = index;
});
},
isScroll: false,
),
Text(
"Index selected : $_tabTextIndexSelected",
),
],
),
),
),
);
}
}
Tried to add obs to the variable _tabTextIndexSelected and obx to everything that is supposed to change, but it doesn't work.
Also, I'm using https://pub.dev/packages/flutter_toggle_tab
this is what I tried (two codes are from different files, I like to try first rather than doing it in my project):
RxInt _tabTextIndexSelected = 0.obs;
final _listTextTabToggle = ["km / m", "m / ft"];
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
Obx(
()=> FlutterToggleTab(
selectedIndex: _tabTextIndexSelected,
selectedBackgroundColors: const [
Colors.blue,
Colors.blueAccent
],
selectedTextStyle: const TextStyle(
color: Colors.white),
unSelectedTextStyle: const TextStyle(),
labels: _listTextTabToggle,
selectedLabelIndex: (index) {
_tabTextIndexSelected = index.obs;
},
isScroll: false,
),
),
Obx(
()=>Text(
"Index selected : $_tabTextIndexSelected",
),
),
The reactive variable and list of tabs string declaration inside the getx controller.
Below is the working snippet to toggle the tabbar.
import 'package:flutter/material.dart';
import 'package:flutter_toggle_tab/flutter_toggle_tab.dart';
import 'package:get/get.dart';
class TestController extends GetxController {
final listTextTabToggle = ["km / m", "m / ft"];
RxInt tabTextIndexSelected = 0.obs;
toggle(int index) => tabTextIndexSelected.value = index;
}
class TestPage extends StatelessWidget {
const TestPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final ctrl = Get.put(TestController());
return SafeArea(
child: Scaffold(
body: Column(children: [
Obx(
() => FlutterToggleTab(
selectedIndex: ctrl.tabTextIndexSelected.value,
selectedBackgroundColors: const [Colors.blue, Colors.blueAccent],
selectedTextStyle: const TextStyle(color: Colors.white),
unSelectedTextStyle: const TextStyle(),
labels: ctrl.listTextTabToggle,
selectedLabelIndex: (index) => ctrl.toggle(index),
isScroll: false,
),
),
Obx(
() => Text(
"Index selected : ${ctrl.tabTextIndexSelected.value}",
),
)
])),
);
}
}
Output:

Flutter stateful widget doesn't change container's color on condition?

In my app I generate a random number between 1-10 and i try to guess. I use container and text and gesture detector for it. I want containers to change color if i click on the right number which i generated randomly. But I don't know why i does not work i tried to solve but i could not. I used initstate or late variable but did not work. help me?
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key})
: super(
key: key,
);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Random random = Random();
late int guessNumber = random.nextInt(9) + 1;
#override
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("My App"),
centerTitle: true,
),
body: Column(
children: [
Expanded(
child: Row(
children: [
Expanded(child: Numb(1)),
Expanded(child: Numb(2)),
Expanded(child: Numb(3)),
],
),
),
Expanded(
child: Row(
children: [
Expanded(child: Numb(4)),
Expanded(child: Numb(5)),
Expanded(child: Numb(6)),
],
),
),
Expanded(
child: Row(
children: [
Expanded(child: Numb(7)),
Expanded(child: Numb(8)),
Expanded(child: Numb(9)),
],
),
),
],
));
}
Widget Numb(int numb) {
Color? color = Colors.lightGreen;
return GestureDetector(
onTap: () {
setState(() {
if (guessNumber == numb) {
color = Colors.pink;
}
});
},
child: Container(
margin: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: color,
),
child: Center(
child: Text(
numb.toString(),
style: const TextStyle(fontSize: 24),
),
),
),
);
}
}
The issue is color is inside the build method(while Numb(int numb) is inside build method) and keep getting Colors.lightGreen; on every setState. Put it outside the build method. like on
class _HomeScreenState extends State<HomeScreen> {
Random random = Random();
late int guessNumber = random.nextInt(9) + 1;
Color? color = Colors.lightGreen;

How do I populate a variable by getting a value from a stateful widget?

I have a variable that is supposed to be populated when an if statement is true.
The if statement is supposed to be true after a value is updated from a stateful widget when pressed.
The stateful widget is _BudgetCategoryCard and it has a bool that is set true when pressed. After being pressed, the value changes and the color of the card turns green as shown in this line: color: widget.hasBeenPressed ? Colors.green : Colors.white
However, after the value of hasBeenPressed has been set true, this if statement should be true but it isn't
if (budgetCategoryCards[index].getHasBeenPressed()) {
setState(() {
selectedBudget = budgetCategoryCards[index].getBudgetName();
});
}
I'm not sure if there is a better way/practice for retrieving values from a stateful widget or if parts of this code should be re-written for improvement but if anyone could recommend changes that would also be tremendously appreciated.
I tried simplifying the code and apologies for the bad code.
Does anyone know why this variable selectedBudget is not getting populated?
main
import 'package:flutter/material.dart';
import 'package:stackoverflow/home_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
List<String> budgets = ["gas", "food", "clothes"];
return MaterialApp(
home: CreateExpenseCardScreen(budgetsList: budgets),
);
}
}
home page
import 'package:flutter/material.dart';
class CreateExpenseCardScreen extends StatefulWidget {
const CreateExpenseCardScreen({
Key? key,
required this.budgetsList,
}) : super(key: key);
final List<String> budgetsList;
#override
State<CreateExpenseCardScreen> createState() =>
_CreateExpenseCardScreenState();
}
class _CreateExpenseCardScreenState extends State<CreateExpenseCardScreen> {
String selectedBudget = "";
#override
Widget build(BuildContext context) {
List<_BudgetCategoryCard> budgetCategoryCards = List.generate(
widget.budgetsList.length,
(index) {
return _BudgetCategoryCard(
budgetName: widget.budgetsList[index],
hasBeenPressed: false,
);
},
);
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 100),
...List.generate(
budgetCategoryCards.length,
(index) {
// why is if statement never true even after pressing card?
//
// as a result, selectedBudget doesnt get assigned a value
if (budgetCategoryCards[index].getHasBeenPressed()) {
setState(() {
selectedBudget = budgetCategoryCards[index].getBudgetName();
});
}
return budgetCategoryCards[index];
},
),
Padding(
padding: const EdgeInsets.all(16.0),
child: GestureDetector(
onTap: () {
if (selectedBudget.isEmpty) {
// send error
} else {
Navigator.pop(
context,
[
selectedBudget,
],
);
}
},
child: Container(
height: 50,
color: Colors.green,
child: const Center(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
"Create",
style: TextStyle(
fontSize: 18,
color: Colors.white,
),
),
),
),
),
),
),
],
),
),
);
}
}
class _BudgetCategoryCard extends StatefulWidget {
_BudgetCategoryCard({
Key? key,
required this.budgetName,
required this.hasBeenPressed,
}) : super(key: key);
final String budgetName;
bool hasBeenPressed;
bool getHasBeenPressed() {
return hasBeenPressed;
}
String getBudgetName() {
return budgetName;
}
#override
State<_BudgetCategoryCard> createState() => _BudgetCategoryCardState();
}
class _BudgetCategoryCardState extends State<_BudgetCategoryCard> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: GestureDetector(
onTap: () {
setState(() {
widget.hasBeenPressed = true;
});
},
child: Container(
height: 50,
color: widget.hasBeenPressed ? Colors.green : Colors.white,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
widget.budgetName,
style: TextStyle(
color: widget.hasBeenPressed
? Colors.white
: Colors.black.withOpacity(0.5),
),
),
),
),
),
),
);
}
}

Bounce Dismissible for helping the user

So we have a Dismissible for confirming/denying a item.
However we have some users that are trying to click/tap on the item.
Our UX team suggested that we then "bounce" the item to show that they have to swipe (and reveal the action fields).
But I don't see any option to do so.
Does anybody have a suggestion what might work for this?
The code I have for now is shown below:
Dismissible(
key: const ValueKey(0),
direction: DismissDirection.horizontal,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 3, vertical: 3),
child: card(),
),
confirmDismiss: (direction) async {
var newStatus = direction == DismissDirection.startToEnd
? OkNokNvt.OK
: OkNokNvt.NOK;
_changeStatus(newStatus);
return false;
},
background: ok(),
secondaryBackground: nok(),
),
The Dismissable doesn't seeem to have this functionality.
Instead, you could use the flutter_slidable package.
Here, you can programmatically open the underlying actions by calling Slideable.of(context)?.open(). No fancy bounce-animation though.
Here's the code:
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bouncing Widget Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Slidable(
key: const Key('key'),
actionPane: const SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
child: Builder(
builder: (context) => GestureDetector(
onTap: () {
Slidable.of(context)
?.open(actionType: SlideActionType.primary);
},
child: Container(
color: Colors.grey,
height: 50,
child: const Center(child: Text('Tap me')),
),
),
),
actions: [
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () => print('remove me from list'),
),
],
dismissal: SlidableDismissal(
onDismissed: (_) => print('remove me from list'),
dragDismissible: true,
child: const SlidableDrawerDismissal(),
),
),
],
),
),
);
}
}
Here is my minimal example which does what you are looking for.
Basically, the GestureDetector onTap callback triggers the animation which has a bouncing-like effect by using a sin function on the _animation.value. The behaviour can be tweeked by changing the parameters cyclesPerAnimation and bounceOffset.
Simply put your Dismissible in the place of the Container and you should be good to go.
environment:
sdk: ">=2.12.0 <3.0.0"
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late final AnimationController _animation = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
Offset _bounceOffset(double animationValue) {
const cyclesPerAnimation = 2;
const bounceOffset = 10;
return Offset(
0,
sin(animationValue * pi * 2 * cyclesPerAnimation) * bounceOffset,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bouncing Widget Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedBuilder(
animation: _animation,
builder: (context, widget) => Transform.translate(
offset: _bounceOffset(_animation.value),
child: GestureDetector(
onTap: () {
_animation.reset();
_animation.forward();
},
child: Container(
color: Colors.grey,
height: 50,
width: 200,
child: const Center(child: Text('Tap to bounce')),
),
),
),
),
],
),
),
);
}
}

Flutter How to pass a parameter (int) to callbacks?

How can I pass a parameter wit callback in Flutter?
I have two files main.dart and block.dart. My goal is to add an int (12 for example) to myCallback in block.dart to use it in main.dart in the function whatToDo (instead of print ('Should receive the Value from myCallback');)
Here is the code of the main.dart File:
import 'package:flutter/material.dart';
import 'block.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
void whatToDo() {
print('Should receive the Value from myCallback');
}
#override
Widget build(BuildContext context) {
// print(getraenke.asMap());
// print(getraenke.asMap().keys);
// print(getraenke);
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Block(
myCallback: whatToDo,
),
),
],
),
),
);
}
}
And here is the Code from block.dart with the callback:
import 'package:flutter/material.dart';
class Block extends StatelessWidget {
final Function myCallback;
Block({this.myCallback});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF722662),
child: Center(
child: GestureDetector(
onTap: myCallback,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
);
}
}
If I understood it correctly, You want your function to accept a parameter.
do it like this.
class Block extends StatelessWidget {
final Function(int num) myCallback;
Block({this.myCallback});
and when you call it, you provide it with the parameter
GestureDetector(
onTap:()=> myCallback(12),
child: ...
and finally you can access it from your main
void whatToDo(int num) {
print(num);
}
Simple way without any advanced topic. Better read some articles about state management. Official documentation.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
void whatToDo(int value) {
print('Should receive the Value from myCallback');
print(value);
}
#override
Widget build(BuildContext context) {
// print(getraenke.asMap());
// print(getraenke.asMap().keys);
// print(getraenke);
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Block(
myCallback: whatToDo,
),
),
],
),
),
);
}
}
class Block extends StatelessWidget {
final void Function(int) myCallback;
Block({required this.myCallback});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF722662),
child: Center(
child: GestureDetector(
onTap: ()=>myCallback(12),
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
);
}
}
in main.dart:
void whatToDo(int value) {
print('the value is $value');
}
in block.dart:
class Block extends StatelessWidget {
final ValueChanged<int> myCallback;
Block({required this.myCallback});
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(10.0),
color: const Color(0xFF722662),
child: Center(
child: GestureDetector(
onTap: () => myCallback(100),
child: const Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
);
}
}
I add more info to Ethsan Askari's answer.
You can define your custom callback and reuse it throughout your app.
typedef OnWhatToDoCallback = Function(int value);
class Block extends StatefulWidget {
const Block({
Key? key,
required this.onWhatToDo,
}) : super(key: key);
final OnWhatToDoCallback onWhatToDo;
...
}