Flutter change int state by get - flutter

I have a simple website menu on clicking it's just changing int value and on the basis of int value it's changing the font color.
I don't want to use setState instead of it I need to use getX I am doing it like this
class SideMenu extends StatefulWidget {
const SideMenu({Key? key}) : super(key: key);
#override
_SideMenuState createState() => _SideMenuState();
}
class _SideMenuState extends State<SideMenu> {
TileColorX tcx = Get.put(TileColorX());
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: [
DrawerHeader(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Dashboard ',
style: Theme.of(context).textTheme.caption!.copyWith(
color: Colors.white,
fontSize: 21,
fontWeight: FontWeight.w700)),
Text('Dashboard',
style: Theme.of(context).textTheme.caption!.copyWith(
color: primaryColor,
fontSize: 21,
fontWeight: FontWeight.w700)),
],
)),
),
DrawerListTile(
title: "Dashboard",
svgSrc: "assets/icons/menu_dashbord.svg",
control: 0,
press: () {
tcx.toggle(0);
},
),
DrawerListTile(
title: "POS and Invoices",
svgSrc: "assets/icons/menu_tran.svg",
control: 1,
press: () {
tcx.toggle(1);
},
),
],
),
);
}
}
class DrawerListTile extends StatelessWidget {
DrawerListTile({
Key? key,
// For selecting those three line once press "Command+D"
required this.title,
required this.svgSrc,
required this.press,
required this.control,
}) : super(key: key);
final String title, svgSrc;
final VoidCallback press;
final int control;
TileColorX tcx = Get.put(TileColorX());
#override
Widget build(BuildContext context) {
return ListTile(
onTap: press,
horizontalTitleGap: 0.0,
leading: SvgPicture.asset(
svgSrc,
color: control == tcx.selectedIndex.value
? Colors.white
: Colors.white54,
height: 16,
),
title: Text(
title,
style: TextStyle(
color: control == tcx.selectedIndex.value
? Colors.white
: Colors.white54),
),
);
}
}
I have a class for toggle
class TileColorX extends GetxController {
RxInt selectedIndex = 0.obs;
void toggle(int index) => selectedIndex.value = index;
}
But it's not changing the state (mean not changing my font color)

You need to use Obx on that widget you want to see change. This will work
return Obx(() => ListTile(
onTap: press,
horizontalTitleGap: 0.0,
leading: SvgPicture.asset(
svgSrc,
color: control == tcx.selectedIndex.value
? Colors.white
: Colors.white54,
height: 16,
),
title: Text(
title,
style: TextStyle(
color: control == tcx.selectedIndex.value
? Colors.white
: Colors.white54),
),
));
I don't know more detailed answer to what Obx exactly did but it will work for you :D

Related

The value entered in TextField is inherited

I'm developing a fill-in-the-blanks quiz app.
There are 5 question statements in one quiz, but when I move on to the next question statement, the value entered in the text field remains. Could you please tell me what are the possible causes?
class PlayGame extends StatefulWidget {
final List document;
List correctList = [];
PlayGame({Key? key, required this.document}) : super(key: key);
#override
State<PlayGame> createState() => _PlayGameState();
}
class _PlayGameState extends State<PlayGame> {
int quizNum = 0;
int quizCount = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Center(
child: Text(
"$quizCount/5",
style: const TextStyle(
fontSize: 25,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold),
),
),
actions: [
Row(
children: [
IconButton(
onPressed: () {
setState(
() {
if (quizNum < 4) {
quizNum += 1;
quizCount += 1;
} else if (quizNum == 4) {
print(widget.correctList.length);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Result()),
);
}
},
);
},
icon: const Icon(
Icons.arrow_circle_right_outlined,
size: 40,
),
),
const SizedBox(
width: 10,
)
],
)
],
automaticallyImplyLeading: false,
),
body: SizedBox(
height: double.infinity,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(bottom: 30.0),
child: TextWithBlanks(
text: widget.document[quizNum],
correctList: widget.correctList),
),
),
),
);
}
}
This is the code I was taught here. Words surrounded by "{}" are BlankWord.
class TextWithBlanks extends StatefulWidget {
final String text;
static final regex = RegExp("(?={)|(?<=})");
List correctList = [];
TextWithBlanks({Key? key, required this.text, required this.correctList})
: super(key: key);
#override
State<TextWithBlanks> createState() => _TextWithBlanksState();
}
class _TextWithBlanksState extends State<TextWithBlanks> {
#override
Widget build(BuildContext context) {
final split = widget.text.split(TextWithBlanks.regex);
return Padding(
padding: const EdgeInsets.only(top: 30.0, right: 30.0, left: 30.0),
child: Text.rich(
TextSpan(
style: const TextStyle(fontSize: 15, height: 3.0),
children: <InlineSpan>[
for (String text in split)
text.startsWith('{')
? WidgetSpan(
child: blankWord(text.substring(1, text.length - 1),
widget.correctList),
)
: TextSpan(text: text),
],
),
),
);
}
}
This is the BlankWord.
class _blankWordState extends State<blankWord> {
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.answerWidth,
child: TextField(
maxLines: null,
cursorColor: Colors.grey,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
autofocus: false,
maxLength: widget.answerLength + 5,
onChanged: (enterWord) {
widget.value = enterWord;
if (enterWord == widget.answer) {
if (widget.answerBool == false) {
widget.answerBool = true;
widget.correctList.add(widget.answer);
}
} else {
if (widget.answerBool == true) {
widget.answerBool = false;
widget.correctList.remove(widget.answer);
}
}
},
decoration: InputDecoration(
counterText: "",
hintText: widget.answerHint,
hintStyle: const TextStyle(color: Colors.grey, fontSize: 12),
),
),
);
}
}
When you update the page by changing the quiz number also reset the value that you are sending to the blank widget. When the blank widget is updated the widget.value is being updated, and that value stays in the class and when a new blank widget is added the value is being sent to the blank widget again I think
widget.value = enterWord;

I would like to keep multiple TextField to hold values

I am developing a fill-in-the-blanks quiz app.
Each quiz contains 5 sentences and they are arranged by PageView. The sentences are retrieved from a List.
Each sentence is a TextWithBlanks class and they have several BlankWord class (which are TextField).
class TextWithBlanks extends StatefulWidget {
final String text;
static final regex = RegExp("(?={)|(?<=})");
List correctList = [];
TextWithBlanks({Key? key, required this.text, required this.correctList})
: super(key: key);
#override
State<TextWithBlanks> createState() => _TextWithBlanksState();
}
class _TextWithBlanksState extends State<TextWithBlanks> {
#override
Widget build(BuildContext context) {
final split = widget.text.split(TextWithBlanks.regex);
return Padding(
padding: const EdgeInsets.only(top: 30.0, right: 30.0, left: 30.0),
child: Text.rich(
TextSpan(
style: const TextStyle(fontSize: 15, height: 3.0),
children: <InlineSpan>[
for (String text in split)
text.startsWith('{')
? WidgetSpan(
child: blankWord(text.substring(1, text.length - 1),
widget.correctList),
)
: TextSpan(text: text),
],
),
),
);
}
}
class blankWord extends StatefulWidget {
final String answer;
int answerLength = 0;
double answerWidth = 0.0;
String answerHint = "";
List correctList;
String value = "";
bool answerBool = false;
blankWord(this.answer, this.correctList, {Key? key}) : super(key: key) {
answerLength = answer.length;
answerWidth = answerLength * 15.0;
answerHint = answer;
}
#override
State<blankWord> createState() => _blankWordState();
}
class _blankWordState extends State<blankWord> {
Widget build(BuildContext context) {
return SizedBox(
width: widget.answerWidth,
child: TextFormField(
maxLines: null,
cursorColor: Colors.grey,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
autofocus: false,
maxLength: widget.answerLength + 5,
onChanged: (enterWord) {
widget.value = enterWord;
if (enterWord == widget.answer) {
if (widget.answerBool == false) {
widget.answerBool = true;
widget.correctList.add(widget.answer);
}
} else {
if (widget.answerBool == true) {
widget.answerBool = false;
widget.correctList.remove(widget.answer);
}
}
},
decoration: InputDecoration(
counterText: "",
hintText: widget.answerHint,
hintStyle: const TextStyle(color: Colors.grey, fontSize: 12),
),
),
);
}
}
If I enter text in one TextWithBlank BlankWord and then enter text in another TextWithBlank BlankWord, what I entered before disappears.
I want to keep the value in the BlankWord (TextField) of each TextWithBlank. What is the best way to do this?
Thank you.
TextWithBlank is included in the QuizText class.
class PlayGame extends StatefulWidget {
final List document;
List correctList = [];
PlayGame({Key? key, required this.document}) : super(key: key);
#override
State<PlayGame> createState() => _PlayGameState();
}
class _PlayGameState extends State<PlayGame> {
int quizNum = 0;
int quizCount = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Center(
child: Text(
"$quizCount/5",
style: const TextStyle(
fontSize: 25,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold),
),
),
actions: [
if (quizCount == 5)
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Result(),
),
);
print(widget.correctList.length);
},
child: Row(
children: const [
Text(
"採点する",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
Icon(
Icons.arrow_forward,
size: 20,
),
SizedBox(
width: 10,
)
],
),
)
else
const SizedBox.shrink()
],
automaticallyImplyLeading: false,
),
body: PageView(
onPageChanged: (counter) {
setState(
() {
quizCount = counter + 1;
},
);
},
children: [
QuizText(widget: widget, quizNum: 0),
QuizText(widget: widget, quizNum: 1),
QuizText(widget: widget, quizNum: 2),
QuizText(widget: widget, quizNum: 3),
QuizText(widget: widget, quizNum: 4)
],
),
);
}
}
class QuizText extends StatelessWidget {
const QuizText({
Key? key,
required this.widget,
required this.quizNum,
}) : super(key: key);
final PlayGame widget;
final int quizNum;
#override
Widget build(BuildContext context) {
return Container(
constraints: const BoxConstraints.expand(),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Card(
child: SizedBox(
height: double.infinity,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(bottom: 30.0),
child: TextWithBlanks(
text: widget.document[quizNum],
correctList: widget.correctList),
),
),
),
),
),
);
}
}
Once the widget is not used, it disposes from widget tree and value lost. You can use state-management property. For now I am using AutomaticKeepAliveClientMixin to preserve the widget .
Changes will be here
class _TextWithBlanksState extends State<TextWithBlanks>
with AutomaticKeepAliveClientMixin {
#override
Widget build(BuildContext context) {
super.build(context);
final split = widget.text.split(TextWithBlanks.regex);
return Padding(
padding: const EdgeInsets.only(top: 30.0, right: 30.0, left: 30.0),
child: Text.rich(
TextSpan(
style: const TextStyle(fontSize: 15, height: 3.0),
children: <InlineSpan>[
for (String text in split)
WidgetSpan(
child: blankWord(
text.substring(1, text.length - 1),
widget.correctList,
),
)
],
),
),
);
}
#override
bool get wantKeepAlive => true;
}

Function callback to change text color (just for one) | Flutter

I'm trying to create a SideMenu with different SideMenuItems.
For that I created a new class and want to update the color of Text when the SideMenuItem is clicked. For that I want to transfer the activeState and all that stuff you see in the code below:
The use of my class in the Widget:
bool isActive = false;
...
SideMenuItem(
icon: Icon(
Icons.inbox,
size: 20,
color: isActive ? kPrimaryColor : kGrayColor,
),
activeState: isActive,
title: "Archiv",
toggleActiveState: (activeState) {
setState(() {
isActive = !activeState;
});
},
),
And here is my class:
import 'package:flutter/material.dart';
import 'package:gastronomy/constants.dart';
class SideMenuItem extends StatelessWidget {
// ignore: prefer_const_constructors_in_immutables
SideMenuItem({
Key? key,
required this.activeState,
this.itemCount = 0,
this.showBorder = true,
#required this.icon,
#required this.title,
required this.toggleActiveState,
}) : super(key: key);
final bool activeState;
final bool showBorder;
final int itemCount;
final Icon? icon;
final String? title;
final Function(bool) toggleActiveState;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: kDefaultPadding),
child: InkWell(
onTap: () {
toggleActiveState(activeState);
},
child: Row(
children: [
const SizedBox(width: 15),
const SizedBox(width: kDefaultPadding / 4),
Expanded(
child: Container(
padding: const EdgeInsets.only(bottom: 15, right: 5),
decoration: showBorder
? const BoxDecoration(
border: Border(
bottom: BorderSide(color: Color(0xFFDFE2EF)),
),
)
: null,
child: Row(
children: [
icon!,
const SizedBox(width: kDefaultPadding * 0.75),
Text(
title!,
style: Theme.of(context).textTheme.button?.copyWith(
color: activeState ? kTextColor : kGrayColor,
),
),
const Spacer(),
// if (itemCount != null) CounterBadge(count: itemCount)
],
),
),
),
],
),
),
);
}
}
I ended up with that pieces of code but well, how you might know, all SideMenuItems change there color when I click one.
I'm pretty new at using this way of code so I would be thankful to all informations you can include into your answer.
One option is to render all the menu items through a map function and compare each item with the selected option, like in the example below:
import 'package:flutter/material.dart';
class MenuExample extends StatefulWidget {
const MenuExample({Key? key}) : super(key: key);
#override
_MenuExampleState createState() => _MenuExampleState();
}
class _MenuExampleState extends State<MenuExample> {
List<String> menuOptions = const ['Item 1', 'Item 2', 'Item 3'];
String selectedOption = '';
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
backgroundColor: Colors.amber,
child: ListView(
children: menuOptions.map((menuOption) {
return InkWell(
onTap: () => setState(() {
selectedOption = menuOption;
}),
child: MenuItem(
name: menuOption,
isSelected: menuOption == selectedOption,
),
);
}).toList()),
),
);
}
}
class MenuItem extends StatelessWidget {
const MenuItem({Key? key, this.isSelected = false, required this.name})
: super(key: key);
final bool isSelected;
final String name;
#override
Widget build(BuildContext context) {
return ListTile(
title: Text(
name,
style: TextStyle(
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal),
),
);
}
}

How to call a function from stateless Widget that points to state class function?

I am trying to create a responsive chatbot with quick replies. I want to make a button on pressed function call to another class's function. I tried using the callback. But i think i am doing something wrong. Kindly help me.
typedef void mycallback(String label);
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
User? user = FirebaseAuth.instance.currentUser;
UserModel loggedInUser = UserModel();
late DialogFlowtter dialogFlowtter;
final TextEditingController messageController = TextEditingController();
#override
void initState() {
super.initState();
DialogFlowtter.fromFile().then((instance) => dialogFlowtter = instance);
}
#override
Widget build(BuildContext context) {
var themeValue = MediaQuery.of(context).platformBrightness;
Body(
hi: sendMessage,
);
return Scaffold(
backgroundColor: themeValue == Brightness.dark
? HexColor('#262626')
: HexColor('#FFFFFF'),
appBar: AppBar(
//app bar ui
),
actions: [
//list if widget in appbar actions
PopupMenuButton(
icon: Icon(Icons.menu),
color: Colors.blue,
itemBuilder: (context) => [
PopupMenuItem<int>(
value: 0,
child: Text(
"Log out",
style: TextStyle(color: Colors.white),
),
),
],
onSelected: (item) => {logout(context)},
),
],
),
body: SafeArea(
child: Column(
children: [
Expanded(child: Body(messages: messages)),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Row(
children: [
Expanded(
child: TextFormField(
controller: messageController,
style: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
fontFamily: 'Poppins'),
decoration: new InputDecoration(
enabledBorder: new OutlineInputBorder(
borderSide: new BorderSide(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
borderRadius: BorderRadius.circular(15)),
hintStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white54
: Colors.black54,
fontSize: 15,
fontStyle: FontStyle.italic,
),
labelStyle: TextStyle(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black),
hintText: "Type here...",
),
),
),
IconButton(
color: themeValue == Brightness.dark
? Colors.white
: Colors.black,
icon: Icon(Icons.send),
onPressed: () {
sendMessage(messageController.text);
messageController.clear();
},
),
],
),
),
],
),
),
);
}
void sendMessage(String text) async {
if (text.isEmpty) return;
setState(() {
//do main function
});
}
}
The class from where i want to call the function
class Body extends StatelessWidget {
final List<Map<String, dynamic>> messages;
final mycallback? hi;
const Body({
Key? key,
this.messages = const [],
this.buttons = const [],
this.hi,
this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (context, i) {
var obj = messages[messages.length - 1 - i];
Message message = obj['message'];
bool isUserMessage = obj['isUserMessage'] ?? false;
String label = obj['label'];
return Row(
mainAxisAlignment:
isUserMessage ? MainAxisAlignment.end : MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
_MessageContainer(
message: message,
isUserMessage: isUserMessage,
),
ElevatedButton(
child: Text(label),
onPressed: () => {hi ?? (label)},//This is where i want to call
style: ElevatedButton.styleFrom(
primary: Colors.blueAccent,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
textStyle: TextStyle(fontWeight: FontWeight.bold)),
),
],
);
},
separatorBuilder: (_, i) => Container(height: 10),
itemCount: messages.length,
reverse: true,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 20,
),
);
}
}
The code runs without errors but nothing happens when i press the buttons.
This is how I'd implement something like that. You're basically asking for a void as parameter inside your widget. Almost like a TextButton or another widget like that.
You can use this with two stateful widets as well, since you're borrowing the function from one to another.
Also I think this would be done better with provider so I suggest you look into it. (I don't have enough experience with it)
https://pub.dev/packages/provider
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int x = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('An app'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$x'),
TestWidget(onTap: () {
setState(() {
x++;
});
})
],
),
),
);
}
}
class TestWidget extends StatelessWidget {
final VoidCallback onTap;
const TestWidget({Key? key, required this.onTap}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(20),
color: Colors.blue,
child: Text('test')),
);
}
}
I found the error.
In the class HomeScreen, I missed this line.
child: Body(
messages: messages,
hi: (text) => {sendMessage(text)}, //this line
)
After adding this line, the callback worked fine!

How to implement this custom slider flutter

I am trying to implement this custom slider on my flutter app. I have searched most of the open source libraries but I cannot seem to get the one that suits my need.
The closet I got to is Cupertino Slider but I couldn't customize it to fit my need. Any ideas?
this is what you are looking for, slider_button:
SliderButton(
action: () {
///Do something here OnSlide
},
///Put label over here
label: Text(
"Slide to cancel !",
style: TextStyle(
color: Color(0xff4a4a4a),
fontWeight: FontWeight.w500,
fontSize: 17),
),
icon: Center(
child: Icon(
Icons.power_settings_new,
color: Colors.white,
size: 40.0,
semanticLabel: 'Text to announce in accessibility modes',
)),
///Change All the color and size from here.
width: 230,
radius: 10,
buttonColor: Color(0xffd60000),
backgroundColor: Color(0xff534bae),
highlightedColor: Colors.white,
baseColor: Colors.red,
);
Try this:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
class View extends StatefulWidget {
const View({Key? key}) : super(key: key);
#override
_ViewState createState() => _ViewState();
}
class _ViewState extends State<View> {
int segmentedControlGroupValue = 0;
final Map<int, Widget> myTabs = const <int, Widget>{
0: Icon(Icons.arrow_forward, color: Colors.white,),
1: Text("Start Shopping", style: TextStyle(color: Colors.orange),)
};
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CupertinoSlidingSegmentedControl(
backgroundColor: Colors.orange.withOpacity(0.2),
groupValue: segmentedControlGroupValue,
thumbColor: CupertinoColors.activeOrange,
children: myTabs,
onValueChanged: (newValue) {
setState(() {
segmentedControlGroupValue = newValue as int;
});
}),
),
);
}
}