How to create a roller like animation? Similar to slot machine - flutter

I want to create a custom animation, basically something like a slot machine, but I want the user to be able to move up/down each block with letters by his finger, not spin automatically.
I tried looking into this library: https://pub.dev/packages/roll_slot_machine/example but doesn't seem to fit my needs. Can I get any hints how to approach this?
What I am trying to achieve:

Using CupertinoPicker can archive similar like this. You can use Stack for background selection, Container's decoration to improve view.
Run on dartPad
class CustomRollStateMachine extends StatefulWidget {
const CustomRollStateMachine({Key? key}) : super(key: key);
#override
_CustomRollStateMachineState createState() => _CustomRollStateMachineState();
}
class _CustomRollStateMachineState extends State<CustomRollStateMachine> {
int aCode = 'A'.codeUnitAt(0);
int zCode = 'Z'.codeUnitAt(0);
late List<String> alphabets = List<String>.generate(
zCode - aCode + 1,
(index) => String.fromCharCode(aCode + index),
);
List<String?> result = List.filled(4, null);
#override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 124,
child: Row(
children: [
Expanded(
child: RollerSlot(
callback: (p0) {
setState(() {
result[0] = p0;
});
},
data: alphabets,
),
),
Expanded(
child: RollerSlot(
callback: (p0) {
setState(() {
result[1] = p0;
});
},
data: alphabets,
),
),
Expanded(
child: RollerSlot(
callback: (p0) {
setState(() {
result[2] = p0;
});
},
data: alphabets,
),
),
Expanded(
child: RollerSlot(
callback: (p0) {
setState(() {
result[3] = p0;
});
},
data: alphabets,
),
),
],
),
),
Text("Result: ${result.join()}")
],
);
}
}
class RollerSlot extends StatelessWidget {
const RollerSlot({
Key? key,
required this.data,
required this.callback,
}) : super(key: key);
final List<String> data;
final Function(String) callback;
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
),
),
child: CupertinoPicker(
itemExtent: 24.0,
onSelectedItemChanged: (value) => callback(data[value]),
children: data
.map(
(e) => Text(e),
)
.toList()),
);
}
}

Related

Show tickmark depending on drop down value in Dart

Need to tickmark this widget depending on drop down value pending
confirmed, dispatched, recieved.
if passed pending it display pending with tick and if its confirmed on
dropdown it shows confimed with two ticks and dispatched with three ticks
and so on. Tried creating drop down which selects the all four values dont understand how
to implement tickmarks based on the text value and show that widget that I made.
Please help. Thanks.
class OrderListScreen extends StatefulWidget {
const OrderListScreen({Key? key}) : super(key: key);
#override
State<OrderListScreen> createState() => _OrderListScreenState();
}
class _OrderListScreenState extends State<OrderListScreen> {
#override
Widget build(BuildContext context) {
return Material(
child: Container(
child: Column(
children: <Widget>[
Text(
" Please select the order status from the dropdown Below:",
style: TextStyle(backgroundColor: Colors.orange)),
Container(
child: Material(
child: DropdownButton<String>(
items: <String>[
'Pending',
'Confirmed',
'Dispatched',
'Recieved'
].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
)),
],
),
),
);
}
}
OrderStatus Widget (that has all dropdown values):
OrderStatusBar(title: widget.order.orderStatus, status: true),
class OrderStatusBar extends StatefulWidget {
const OrderStatusBar({Key? key, required this.title, required this.status})
: super(key: key);
final String title;
final bool status;
#override
State<OrderStatusBar> createState() => _OrderStatusBarState();
}
class _OrderStatusBarState extends State<OrderStatusBar> {
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Row(
children: [
widget.status ? dottedCircleWithCheckMark() : dottedCircle(),
const SizedBox(width: 30),
Text(
widget.title.tr,
style: TextStyle(
fontSize: 20,
fontWeight: widget.status ? FontWeight.bold : null,
),
),
],
),
);
}
}
const size = 25.0;
const strokeWidth = 1.0;
const checkedColor = Color.fromRGBO(232, 113, 65, 1);
Widget dottedLine() {
return Directionality(
textDirection: TextDirection.rtl,
child: Align(
alignment: Alignment.topRight,
child: Container(
margin: const EdgeInsets.fromLTRB(0, 0, size / 2, 0),
child: const Padding(
padding: EdgeInsets.only(left: 27 / 2),
child: SizedBox(
height: size,
child: DottedLine(
dashColor: Colors.black,
direction: Axis.vertical,
lineLength: size,
lineThickness: strokeWidth,
dashLength: 5,
dashGapLength: 5,
),
),
),
),
),
);
}
dottedCircle() {
return DottedBorder(
borderType: BorderType.Circle,
dashPattern: const [5, 5],
child: Container(
height: size,
width: size,
decoration: const BoxDecoration(shape: BoxShape.circle),
));
}
dottedCircleWithCheckMark() {
return Container(
height: size + strokeWidth * 2,
width: size + strokeWidth * 2,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: checkedColor,
),
child: const Icon(
Icons.check,
color: Colors.white,
size: size / 4 * 3,
),
);
}
Create a callback on OrderListScreen to get selected item.
class OrderListScreen extends StatefulWidget {
final Function(String? selectedValue) callback;
const OrderListScreen({Key? key, required this.callback}) : super(key: key);
#override
State<OrderListScreen> createState() => _OrderListScreenState();
}
And get value from from onCHanged
onChanged: (v) {
widget.callback(v);
setState(() {
selectedValue = v;
});
},
Now on parent widget.
class _AppXState extends State<AppX> {
final items = <String>['Pending', 'Confirmed', 'Dispatched', 'Recieved'];
int selectedItemIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
OrderListScreen(
callback: (selectedValue) {
if (selectedValue != null && items.contains(selectedValue)) {
selectedItemIndex = items.indexOf(selectedValue);
setState(() {});
}
},
),
for (int i = 0; i < items.length; i++)
OrderStatusBar(title: items[i], status: i <= selectedItemIndex),
],
),
);
}
}
Test snippet
class AppX extends StatefulWidget {
AppX({Key? key}) : super(key: key);
#override
State<AppX> createState() => _AppXState();
}
class _AppXState extends State<AppX> {
final items = <String>['Pending', 'Confirmed', 'Dispatched', 'Recieved'];
int selectedItemIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
OrderListScreen(
callback: (selectedValue) {
if (selectedValue != null && items.contains(selectedValue)) {
selectedItemIndex = items.indexOf(selectedValue);
setState(() {});
}
},
),
for (int i = 0; i < items.length; i++)
OrderStatusBar(title: items[i], status: i <= selectedItemIndex),
],
),
);
}
}
class OrderListScreen extends StatefulWidget {
final Function(String? selectedValue) callback;
const OrderListScreen({Key? key, required this.callback}) : super(key: key);
#override
State<OrderListScreen> createState() => _OrderListScreenState();
}
class _OrderListScreenState extends State<OrderListScreen> {
String? selectedValue;
#override
Widget build(BuildContext context) {
return Material(
child: Container(
child: Column(
children: <Widget>[
Text(" Please select the order status from the dropdown Below:",
style: TextStyle(backgroundColor: Colors.orange)),
Container(
child: Material(
child: DropdownButton<String>(
value: selectedValue,
items: <String>[
'Pending',
'Confirmed',
'Dispatched',
'Recieved'
].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Row(
children: [
Text(value),
],
),
);
}).toList(),
onChanged: (v) {
widget.callback(v);
setState(() {
selectedValue = v;
});
},
),
)),
],
),
),
);
}
}

Want to highlight selected widget in flutter

I have made an demo app where I have created a custom widget and using this custom widget many times. now I want to highlight widget with different colour than others on tap..like BottomNavigationBarItem showing selected barite with differ colour than other
what should I implement to do it...specially any short way so that it can work with many same widgets..
here is my simple coding..
my custom widget
class MyContainer extends StatelessWidget {
final VoidCallback ontap;
MyContainer({required this.ontap});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10),
child: GestureDetector(
onTap: ontap,
child: Container(
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(20),
//border:isselected==true? Border.all(width: 2,color: Colors.blue):null,
),
),
),
);
}
}
and here is home file
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: Row(
children: [
Expanded(child: MyContainer(
ontap: () {
setState(() {});
},
)),
Expanded(child: MyContainer(
ontap: () {
setState(() {});
},
))
],
)),
Expanded(child: MyContainer(
ontap: () {
setState(() {});
},
)),
],
),
);
}
}
You can use nullable int to hold selected index, and index can be considered as widget ID. Also pass the bool to show selected condition.
class MyContainer extends StatelessWidget {
final VoidCallback ontap;
bool isSelected;
MyContainer({
required this.ontap,
this.isSelected = false,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10),
child: GestureDetector(
onTap: ontap,
child: Container(
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(20),
border: isSelected == true
? Border.all(width: 2, color: Colors.blue)
: null,
),
),
),
);
}
}
class HomeScreen extends StatefulWidget {
HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int? selectedIndex;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: MyContainer(
isSelected: selectedIndex == 1,
ontap: () {
selectedIndex = 1;
setState(() {});
},
),
),
Expanded(
child: MyContainer(
isSelected: selectedIndex == 2,
ontap: () {
selectedIndex = 2;
setState(() {});
},
),
)
],
)),
Expanded(
child: MyContainer(
isSelected: selectedIndex == 3,
ontap: () {
selectedIndex = 3;
setState(() {});
},
),
),
],
),
);
}
}

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),
),
),
),
),
),
),
);
}
}

How do I reset my controller when I come back or finish?

I have a QuestionController class extends GetxController
When I exit the Page using the controls, I want it to stop working (because it is still running in the background) and to start again if I come back to that page.
I've tried: I added these after the route of the ScoreScreen() (in nextQuestion ()) :
_isAnswered = false;
_questionNumber.value = 1;
I reset the values ​​before going to the score page. It may work if you go to the score page, but if you come back earlier, it won't. (up side Question num/4 does not work here). So this way is not suitable.
What is the way I can stop and reset it when the page exits?
Controller class code:
class QuestionController extends GetxController
with SingleGetTickerProviderMixin {
PageController _pageController;
PageController get pageController => this._pageController;
List<Question> _questions = questions_data
.map(
(e) => Question(
id: e["id"],
question: e["question"],
options: e["options"],
answer: e["answer_index"]),
)
.toList();
List<Question> get questions => this._questions;
bool _isAnswered = false;
bool get isAnswered => this._isAnswered;
int _correctAns;
int get correctAns => this._correctAns;
int _selectedAns;
int get selectedAns => this._selectedAns;
RxInt _questionNumber = 1.obs;
RxInt get questionNumber => this._questionNumber;
int _numOfCorrectAns = 0;
int get numOfCorrectAns => this._numOfCorrectAns;
#override
void onInit() {
_pageController = PageController();
super.onInit();
}
#override
void onClose() {
super.onClose();
_pageController.dispose();
}
void checkAns(Question question, int selectedIndex) {
_isAnswered = true;
_correctAns = question.answer;
_selectedAns = selectedIndex;
if (_correctAns == _selectedAns) _numOfCorrectAns++;
update();
Future.delayed(Duration(seconds: 2), () {
nextQuestion();
});
}
void nextQuestion() {
if (_questionNumber.value != _questions.length) {
_isAnswered = false;
_pageController.nextPage(
duration: Duration(milliseconds: 300), curve: Curves.ease);
} else {
Get.off(ScoreScreen(correctNum: _numOfCorrectAns)); // GetMaterialApp()
// _isAnswered = false;
_numOfCorrectAns = 0;
//_questionNumber.value = 1;
}
}
void updateTheQuestionNum(int index) {
_questionNumber.value = index + 1;
}
}
Full code below
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:get/get.dart'; // get: ^3.25.4
// QuizPage() ===============> 50. line (Question 1/4) 81. line
// QuestionCard() ==============> 116. line
// Option() ===================> 163. line
// QuestionController() ========> 218. line
// ScoreScreen() ================> 345. line
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(canvasColor: Colors.blue),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
),
body: Center(
child: InkWell(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => QuizPage()));
},
child: Container(
padding: EdgeInsets.all(22),
color: Colors.green,
child: Text(
"Go Quiz Page",
style: TextStyle(color: Colors.white),
),
),
),
),
);
}
}
class QuizPage extends StatelessWidget {
const QuizPage({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
QuestionController _questionController = Get.put(QuestionController());
return Scaffold(
appBar: AppBar(
title: Text("Quiz Page"),
),
body: Stack(
children: [
SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 16,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Obx(
() => Center(
child: RichText(
text: TextSpan(
// text,style default adjust here OR:children[TextSpan(1,adjust 1),TextSpan(2,adjust 2),..]
text:
"Question ${_questionController._questionNumber.value}",
style: TextStyle(
fontSize: 33, color: Colors.white70),
children: [
TextSpan(
text:
"/${_questionController._questions.length}",
style: TextStyle(fontSize: 25))
])),
),
),
),
Divider(color: Colors.white70, thickness: 1),
SizedBox(
height: 16,
),
Expanded(
child: PageView.builder(
physics: NeverScrollableScrollPhysics(),
controller: _questionController._pageController,
onPageChanged: _questionController.updateTheQuestionNum,
itemCount: _questionController.questions.length,
itemBuilder: (context, index) => QuestionCard(
question: _questionController.questions[index],
),
),
)
],
),
)
],
),
);
}
}
class QuestionCard extends StatelessWidget {
final Question question;
const QuestionCard({
Key key,
#required this.question,
}) : super(key: key);
#override
Widget build(BuildContext context) {
QuestionController _controller = Get.put(QuestionController());
return Container(
margin: EdgeInsets.only(left: 16, right: 16, bottom: 16),
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
color: Colors.white,
),
child: Column(
children: [
Text(
question.question,
style: TextStyle(fontSize: 22),
),
SizedBox(
height: 8,
),
Flexible(
child: SingleChildScrollView(
child: Column(
children: [
...List.generate(
question.options.length,
(index) => Option(
text: question.options[index],
index: index,
press: () => _controller.checkAns(question, index)))
],
),
),
)
],
),
);
}
}
class Option extends StatelessWidget {
final String text;
final int index;
final VoidCallback press;
const Option({
Key key,
#required this.text,
#required this.index,
#required this.press,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetBuilder<QuestionController>(
init: QuestionController(),
builder: (q) {
Color getRightColor() {
if (q.isAnswered) {
if (index == q._correctAns) {
return Colors.green;
} else if (index == q.selectedAns &&
q.selectedAns != q.correctAns) {
return Colors.red;
}
}
return Colors.blue;
}
return InkWell(
onTap: press,
child: Container(
//-- Option
margin: EdgeInsets.only(top: 16),
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: getRightColor(),
borderRadius: BorderRadius.circular(16)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${index + 1}. $text",
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
),
),
);
});
}
}
class QuestionController extends GetxController
with SingleGetTickerProviderMixin {
PageController _pageController;
PageController get pageController => this._pageController;
List<Question> _questions = questions_data
.map(
(e) => Question(
id: e["id"],
question: e["question"],
options: e["options"],
answer: e["answer_index"]),
)
.toList();
List<Question> get questions => this._questions;
bool _isAnswered = false;
bool get isAnswered => this._isAnswered;
int _correctAns;
int get correctAns => this._correctAns;
int _selectedAns;
int get selectedAns => this._selectedAns;
RxInt _questionNumber = 1.obs;
RxInt get questionNumber => this._questionNumber;
int _numOfCorrectAns = 0;
int get numOfCorrectAns => this._numOfCorrectAns;
#override
void onInit() {
_pageController = PageController();
//_pageController.addListener(() { _questionNumber.value = _pageController.page.round()+1; });
super.onInit();
}
#override
void onClose() {
super.onClose();
_pageController.dispose();
}
void checkAns(Question question, int selectedIndex) {
_isAnswered = true;
_correctAns = question.answer;
_selectedAns = selectedIndex;
if (_correctAns == _selectedAns) _numOfCorrectAns++;
update();
Future.delayed(Duration(seconds: 2), () {
nextQuestion();
});
}
void nextQuestion() {
if (_questionNumber.value != _questions.length) {
_isAnswered = false;
_pageController.nextPage(
duration: Duration(milliseconds: 300), curve: Curves.ease);
} else {
Get.off(ScoreScreen(correctNum: _numOfCorrectAns)); // GetMaterialApp()
// _isAnswered = false;
_numOfCorrectAns = 0;
//_questionNumber.value = 1;
}
}
void updateTheQuestionNum(int index) {
_questionNumber.value = index + 1;
}
}
class Question {
final int id, answer;
final String question;
final List<String> options;
Question({
#required this.id,
#required this.question,
#required this.options,
#required this.answer,
});
}
const List questions_data = [
{
"id": 1,
"question": "Question 1",
"options": ['option A', 'B', 'C', 'D'],
"answer_index": 3,
},
{
"id": 2,
"question": "Question 2",
"options": ['option A', 'B', 'C', 'D'],
"answer_index": 2,
},
{
"id": 3,
"question": "Question 3",
"options": ['option A', 'B', 'C', 'D'],
"answer_index": 0,
},
{
"id": 4,
"question": "Question 4",
"options": ['option A', 'B', 'C', 'D'],
"answer_index": 0,
},
];
class ScoreScreen extends StatelessWidget {
final int correctNum;
ScoreScreen({#required this.correctNum});
#override
Widget build(BuildContext context) {
QuestionController _qController = Get.put(QuestionController());
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: [
Column(
children: [
Spacer(
flex: 2,
),
Text(
"Score",
style: TextStyle(fontSize: 55, color: Colors.white),
),
Spacer(),
Text(
"${correctNum * 10}/${_qController.questions.length * 10}",
style: TextStyle(fontSize: 33, color: Colors.white),
),
Spacer(
flex: 2,
),
InkWell(
onTap: () => Get.back(),
borderRadius: BorderRadius.circular(16),
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white24),
child: Text(
"Back to Home Page",
style: TextStyle(color: Colors.white),
),
),
),
Spacer(),
],
),
],
),
);
}
}
If you want to reset only one controller then you can use Get.delete<ExecutableController>();
for resetting all controller Get.deleteAll();
Updated Answer:
Ok, after seeing your full code my solution requires a couple extra steps.
Add this to your controller class. It needs to be called in the onPressed from your HomeScreen
void resetQuestionNumber() => _questionNumber.value = 1;
You'll have to initialize the controller earlier so you can add this in your HomeScreen
final _questionController = Get.put(QuestionController());
The onTap of your HomeScreen now looks like this.
onTap: () {
_questionController.resetQuestionNumber();
Navigator.push(
context, MaterialPageRoute(builder: (context) => QuizPage()));
},
That should do it. The _pageController index wasn't updated until after a question was answered you so just need to reset _questionNumber before going to QuizPage and after that it catches up. Your updateTheQuestionNum can go away completely and you don't need to handle anything this in the onPageChanged of the PageView.builder anymore.
Original Answer:
If you just want that RxInt _questionNumber to match the value of the _pageController you could add a listener in your onInit
_pageController.addListener(() {
_questionNumber.value = _pageController.page.round() + 1;
});
Edit: Added + 1 to account for index starting at 0
you can listen to "onBack event" and dispose the controller
here is an example
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
disposeController(context);
},
child: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
_moveToSignInScreen(context);
}),
title: Text("Profile"),
),
),
);
}
void disposeController(BuildContext context){
//or what you wnat to dispose/clear
_pageController.dispose()
}
InkWell(
onTap: () {
/*add QuestionController().refresh();*/
QuestionController().refresh();
Get.back();
},
borderRadius: BorderRadius.circular(16),
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.white24),
),
child: Text(
Back to Home Page",
style: TextStyle(color: Colors.white),
),
),
),
Automatically:
Get.to(() => DashboardPage(), binding: BindingsBuilder.put(() => DashboardController()));
Manually:
U can delete the controller on back btn then put it again it will give the same result as resetting the controller:
delete it:
Get.delete();
Add it again:
Get.put(DashboardController());
You can use Get.reset() if you only have one controller. It clears all registered instances.

Access List from statefulwidget to state

I want to pass a List from screen 1 to screen 2 statefulwidget and want to add data to it.
List type Question,
class Question {
String questionText;
String answerText;
Question({this.questionText, this.answerText});
}
I passed the list to 2nd screen
class CardPage extends StatefulWidget {
final List<Question> questionBank;
CardPage({#required this.questionBank});
#override
......
I added the content to the list from state,
TextField(onChanged: (text) {question = text;}),
TextField(onChanged: (text) {answer = text;}),
FlatButton(
child: Text("Create"),
onPressed: () {setState(() {
questionBank.add(Question(questionText: question, answerText: answer));});
}
)
Bt I don't know how to connect the List in stateful widget to the state to access it. I know there is widget for it but don't know how to completely import the list to state with it.
Anyone help me
You can pass a function instead of list to your CardPage. It should be called when you create a new question. I think it is the most simple solution.
You CardPage should be like this:
class CardPage extends StatefulWidget {
final Function(Question) createQuestion;
CardPage({Key key, #required this.createQuestion}) : super(key: key);
#override
State<StatefulWidget> createState() => _CardPageState();
}
class _CardPageState extends State<CardPage> {
String _question = '';
String _answer = '';
#override
Widget build(BuildContext context) {
return Column(children: [
TextField(onChanged: (text) {
_question = text;
}),
TextField(onChanged: (text) {
_answer = text;
}),
FlatButton(
child: Text("Create"),
onPressed: () {
setState(() {
final question =
Question(questionText: _question, answerText: _answer);
widget.createQuestion(question);
});
})
]);
}
}
Question lists owner state should be like this:
class _FirstWidgetState extends State<FirstWidget> {
final List<Question> questionBank = [];
#override
Widget build(BuildContext context) {
return ...
CardPage(createQuestion: _createQuestion);
...
}
void _createQuestion(Question question) {
setState(() {
questionBank.add(question);
});
}
}
Try this
simple demo.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
#override
_State createState() => _State();
}
class _State extends State<MyApp> {
final List<String> names = <String>['apple', 'samsung', 'shirsh'];
TextEditingController nameController = TextEditingController();
void addItemToList(){
setState(() {
names.insert(0,nameController.text);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Column(
children: <Widget>[
Row(
children: [
Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.all(20),
child: TextField(
controller: nameController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Contact Name',
),
),
),
),
Expanded(
flex: 2,
child: RaisedButton(
child: Text('Add Item'),
onPressed: () {
if(nameController.text.toString()!="")
addItemToList();
},
),
)
],
),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: names.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 50,
margin: EdgeInsets.all(2),
color: Colors.cyan,
child: Center(
child: Text('${names[index]}',
style: TextStyle(fontSize: 18),
)
),
);
}
)
)
]
)
);
}
}