Related
I have an increment button with a callback function:
class IncrementButton extends StatelessWidget {
final VoidCallback callback;
const IncrementButton({
Key? key,
required this.callback,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
callback();
},
onLongPressStart: ((details) {
callback();
}),
......
);
}
}
And using it as:
IncrementButton(
callback: _increment,
),
The _increment function is as:
_increment() {
value += 1;
}
What I want is when the user taps once, the _increment function will be called. But when the user keeps a long press on the button, the same increment function should be called. But that doesn't happen. The _increment method is getting called only once for long Press
I guess you want the number to be incremented continually while long pressing the button/container. You need a timer which starts when onLongPress gets called. The timer stops when ´onLongPressEnd` gets called.
Try this:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String action = "START";
Timer? timer;
int number = 0;
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: const Text('Material App Bar'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(action),
SizedBox(height: 50),
Material(
borderRadius: BorderRadius.circular(20),
elevation: 20,
child: GestureDetector(
onTap: () => setState(() {
action = "Tap";
number++;
}),
onLongPress: () => setState(() {
timer = Timer.periodic(Duration(milliseconds: 50), (timer) {
setState(() {
action = "Longpress started";
number++;
});
});
}),
onLongPressEnd: (_) => setState(() {
action = "Longpress stopped";
timer?.cancel();
}),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.red[50],
borderRadius: BorderRadius.circular(20)
),
width: 100,
height: 100,
child: Text('Tap')
),
),
),
SizedBox(height: 50,),
Text(number.toString())
],
),
),
),
);
}
#override
void dispose() {
timer?.cancel();
super.dispose();
}
}
Proof:
Change your onlongpressStart.
do{
callback();
} while(btnPressed);
And on onlongpressEnd
setState(() => btnPressed = false);
I have a loop that prints "hello world" 100 times. so what i want is to show progress Indicator which shows the loop progress..
for example: if the loop printed 50 time from total 100 time the progress Indicator should be at 50 percent..
Like #pskink mentioned in the comments, a LinearProgressIndicator or CircularProgressIndicator should do the trick. Do go into a bit more detail, you can store the progress after each iteration (or every so many iterations depending on your needs), and if you use your widget's state for it, a rebuild should automatically trigger and rebuild the progress indicator with the new value each time. That could look a bit like:
// inside the State
double progress = 0.0;
doTheLoop() {
for (int i = 0; i < 100; i++) {
print('Hello world');
setState(() => progress = i/100);
}
}
build(BuildContext context) {
return Column(children: [
Container(
// the progress indicator updates when the progress variable in the state updates, since a rebuild is triggered
child: LinearProgressIndicator(
progress: progress,
);
),
// press the button to start the loop
ElevatedButton(
child: Text('Start loop'),
onPressed: doTheLoop,
),
],),
}
Here Direct Setstate not work because for loop execute as soon as possible.So we add 100 millisecond time delay for visual progress
await Future.delayed(Duration(milliseconds: 100));
Linewar Widget
LinearProgressIndicator(
minHeight: 25,
value: _value,
color: _color,
semanticsValue: (_value * 100).toString(),
semanticsLabel: (_value * 100).toString(),
)
while Press loopbutton
Future<void> loop() async {
for (int i = 0; i <= 100; i++) {
await Future.delayed(Duration(milliseconds: 100));
var element = i;
print(element);
setState(() {
_value = element / 100;
print(_value);
});
if (element < 5 && element > 0)
_color = Colors.red;
else if (element < 25 && element > 5)
_color = Colors.cyan;
else if (element < 50 && element > 25)
_color = Colors.lightGreenAccent;
else if (element < 75 && element > 50)
_color = Colors.lightGreen;
else if (element < 100 && element > 75) _color = Colors.green;
}
}
Without Streamcontroller dartpad
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: "/",
routes: {
"/": (context) => Home(),
},
title: _title,
// home: ,
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("title")),
body: const Center(
child: MyStatelessWidget(),
),
);
}
}
var _color = Colors.black;
var _value = 0.0;
class MyStatelessWidget extends StatefulWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
State<MyStatelessWidget> createState() => _MyStatelessWidgetState();
}
class _MyStatelessWidgetState extends State<MyStatelessWidget> {
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(8),
child: Stack(
children: [
Positioned(
child: Container(
height: 100,
width: 100,
child: CircularProgressIndicator(
strokeWidth: 4,
value: _value,
color: _color,
),
),
top: 0,
left: 0,
right: 0,
bottom: 0,
),
Positioned(
child: Text(
(_value * 100).toStringAsFixed(1),
style: TextStyle(fontSize: 15),
),
top: 25,
left: 10,
),
],
),
height: 75,
width: 75,
),
Container(
padding: EdgeInsets.all(8),
child: LinearProgressIndicator(
minHeight: 25,
value: _value,
color: _color,
semanticsValue: (_value * 100).toString(),
semanticsLabel: (_value * 100).toString(),
)),
Text(
(_value * 100).toStringAsFixed(1),
style: TextStyle(fontSize: 25),
),
Row(
children: [
Expanded(
child: IconButton(
onPressed: () {
loop();
},
icon: Icon(
Icons.not_started_outlined,
size: 45,
),
),
),
Expanded(
child: IconButton(
onPressed: () {},
icon: Icon(Icons.stop, size: 45),
),
),
],
),
],
),
);
}
Future<void> loop() async {
for (int i = 0; i <= 100; i++) {
// if (!stream.isClosed) stream.sink.addStream(Stream.value(i));
await Future.delayed(Duration(milliseconds: 100));
var element = i;
print(element);
setState(() {
_value = element / 100;
print(_value);
});
if (element < 5 && element > 0)
_color = Colors.red;
else if (element < 25 && element > 5)
_color = Colors.cyan;
else if (element < 50 && element > 25)
_color = Colors.lightGreenAccent;
else if (element < 75 && element > 50)
_color = Colors.lightGreen;
else if (element < 100 && element > 75) _color = Colors.green;
}
}
#override
void initState() {}
}
This Sample .Here use streamcontroller .so using stream controller mange the progress like pause or stop the progress.
SampleCode Dart pad Live code
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: "/",
routes: {
"/": (context) => Home(),
},
title: _title,
// home: ,
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("title")),
body: const Center(
child: MyStatelessWidget(),
),
);
}
}
var _color = Colors.black;
var _value = 0.0;
class MyStatelessWidget extends StatefulWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
State<MyStatelessWidget> createState() => _MyStatelessWidgetState();
}
class _MyStatelessWidgetState extends State<MyStatelessWidget> {
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(8),
child: Stack(
children: [
Positioned(
child: Container(
height: 100,
width: 100,
child: CircularProgressIndicator(
strokeWidth: 4,
value: _value,
color: _color,
),
),
top: 0,
left: 0,
right: 0,
bottom: 0,
),
Positioned(
child: Text(
(_value * 100).toStringAsFixed(1),
style: TextStyle(fontSize: 15),
),
top: 25,
left: 10,
),
],
),
height: 75,
width: 75,
),
Container(
padding: EdgeInsets.all(8),
child: LinearProgressIndicator(
minHeight: 25,
value: _value,
color: _color,
semanticsValue: (_value * 100).toString(),
semanticsLabel: (_value * 100).toString(),
)),
Text(
(_value * 100).toStringAsFixed(1),
style: TextStyle(fontSize: 25),
),
Row(
children: [
Expanded(
child: IconButton(
onPressed: () {
loop();
},
icon: Icon(
Icons.not_started_outlined,
size: 45,
),
),
),
Expanded(
child: IconButton(
onPressed: () {
stream.close();
},
icon: Icon(Icons.stop, size: 45),
),
),
],
),
],
),
);
}
Future<void> loop() async {
for (int i = 0; i <= 100; i++) {
if (!stream.isClosed) stream.sink.addStream(Stream.value(i));
await Future.delayed(Duration(milliseconds: 100));
}
// List.generate(100, (index) => index + 1).forEach((element) async {
// if (!stream.isClosed) stream.sink.addStream(Stream.value(element));
// await Future.delayed(Duration(seconds: 1));
// });
}
// late StreamController<int> stream;
StreamController<int> stream = StreamController();
#override
void initState() {
stream.stream.listen((element) {
print(element);
setState(() {
_value = element / 100;
print(_value);
});
if (element < 5 && element > 0)
_color = Colors.red;
else if (element < 25 && element > 5)
_color = Colors.cyan;
else if (element < 50 && element > 25)
_color = Colors.lightGreenAccent;
else if (element < 75 && element > 50)
_color = Colors.lightGreen;
else if (element < 100 && element > 75) _color = Colors.green;
});
}
}
please try this
class testwidget extends StatefulWidget {
const testwidget({Key? key}) : super(key: key);
#override
_test createState() => _test();
}
class _test extends State<testwidget> {
StreamController loopValueStram=new StreamController();
var loopProgress=0.0;
static const max=100;
#override
void initState() {
// TODO: implement initState
super.initState();
loopValueStram.stream.listen((event) {
setState(() {
loopProgress=event;
});
});
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('test'),
),
body: Center(
child:Column(
children: [
RaisedButton(
onPressed: (){
loop();
},
child: Text("Start loop ${(loopProgress*100).toInt()}%"),
),
SizedBox(height: 10,),
Padding(padding: EdgeInsets.all(20),
child: Visibility(
visible:loopProgress>0,
child: LinearProgressIndicator(
value: loopProgress.toDouble(),
semanticsLabel: "Progress",
minHeight: 40,
)),
)
],
)
)
);
}
Future<void> loop() async {
for(int i=0;i<=100;i++){
loopValueStram.sink.add(i/100);
await Future.delayed(Duration(seconds: 1));// this line is to slowdown itération so we can see linear pregression well
}
}
}
I have checked mukltiple posts on this matter, but none has helped, while some stopped the error (e.g. adding a variable that stops the function to notifylistener after its disposed), it certainly didnt fix it.
My Goal is to make a shopping list that just records the state of each checkbox in a tab and displays it using navigator.push and back using pop
Source Code:
home.dart
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:loginpage/main.dart';
import 'package:badges/badges.dart';
import 'package:provider/provider.dart';
import 'tabPage.dart';
import 'mobileList.dart';
import 'itemList.dart';
class HomePage extends StatefulWidget {
HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
LoginPage loginPage = LoginPage();
TabPage? tabPage;
#override
void initState() {
super.initState();
tabPage = TabPage(
key: GlobalKey<TabPageState>(),
tabNum: 10,
controlNum: 3,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
leading: IconButton(
onPressed: () {
//Back to Login Page
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()));
},
icon: Image.asset('assets/images/backbtn.png'),
),
actions: [
ChangeNotifierProvider(
create: (context) => tabPage!.checkBoxInfo,
child: Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return Badge(
position: BadgePosition.topEnd(top: 0, end: 0),
shape: BadgeShape.square,
borderRadius: BorderRadius.circular(20),
badgeContent: Text(checkBoxInfo.checked.toString()),
animationType: BadgeAnimationType.scale,
animationDuration: Duration(milliseconds: 50),
child: IconButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ItemList(
checkBoxInfo: tabPage!.checkBoxInfo)));
},
icon: Icon(Icons.shopping_cart)),
);
},
),
),
],
),
body: SafeArea(
child: Scaffold(
body: Center(
child: Column(
children: <Widget>[
SizedBox(height: 30),
Text('This is the Home Page'),
SizedBox(height: 20),
Text(loginPage.username),
//Tab Page
Container(
child: tabPage,
),
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MobileList(data: data)));
},
child: Text("Mobile List")),
],
),
),
),
),
floatingActionButton: Container(
decoration:
BoxDecoration(color: Colors.grey[800], shape: BoxShape.circle),
child: IconButton(
color: Colors.lightBlue,
onPressed: () {
// tabPage!.tabindex == tabPage!.tabNum - 1
// ? tabPage!.tabindex = 0
// : tabPage!.tabindex += 1;
// //callback method
// //GlobalKey method
// //Set Global Key
// (tabPage!.key as GlobalKey<TabPageState>) //Casting
// .currentState
// ?.tabSetState();
// // tabPageKey.currentState?.tabSetState();
(tabPage!.key as GlobalKey<TabPageState>)
.currentState!
.scrollToOffset(100, Duration(milliseconds: 200));
},
icon: const Icon(Icons.ac_unit_outlined)),
),
);
}
}
tabPage.dart
import 'package:flutter/material.dart';
import 'dart:developer';
import 'package:loginpage/pages/home.dart';
class TabPage extends StatefulWidget {
TabPage({Key? key, required this.tabNum, required this.controlNum})
: super(key: key);
final int controlNum;
final int tabNum;
final String _example = "";
CheckBoxInfo checkBoxInfo = CheckBoxInfo();
int tabindex = 0;
#override
State<StatefulWidget> createState() => TabPageState();
}
class TabPageState extends State<TabPage> {
List<String> tabTitles = [];
List<List<Widget>> tabs = [];
ScrollController? _scrollController;
void scrollToOffset(increment, duration) {
_scrollController!.animateTo(_scrollController!.offset + increment,
duration: duration, curve: Curves.ease);
}
void tabSetState() {
setState(() {});
}
#override
void initState() {
super.initState();
tabTitles = createTabTitles(widget.tabNum);
_scrollController = ScrollController(initialScrollOffset: 20);
_scrollController!.addListener(() {
print(_scrollController!.offset);
});
widget.checkBoxInfo
.initCheckBox(widget.controlNum, widget.tabNum, tabTitles);
}
#override
Widget build(BuildContext context) {
tabs = createTabs(widget.tabNum);
return SafeArea(
child: Column(
children: [
SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.only(left: 20.0, right: 20.0),
decoration: BoxDecoration(
border: Border.all(width: 3, color: Colors.black)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _scrollController,
child: Row(
// children: tabTitles
// .asMap()
// .map((i, title) => MapEntry(
// i,
// TextButton(
// onPressed: () {
// setState(() {
// widget.tabindex = i;
// });
// },
// child: Text(tabTitles[i]),
// )))
// .values
// .toList()
// children: tabTitles.map((title) => TextButton(
// onPressed: () {
// setState(() {
// widget.tabindex = i;
// });
// },
// child: Text(tabTitles[i]),
// )).toList(),
children: createTabBtns(),
),
),
Padding(
padding: EdgeInsets.all(5),
child: Column(
children: tabs[widget.tabindex],
),
)
]),
),
],
),
);
}
List<Widget> createTabBtns() {
List<Widget> btnList = [];
for (int i = 0; i < tabTitles.length; i++) {
btnList.add(Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(width: 1, color: Colors.grey),
bottom: widget.tabindex == i
? BorderSide(width: 4, color: Colors.blue[400]!)
: BorderSide(width: 4, color: Colors.grey[400]!))),
child: TextButton(
onPressed: () {
setState(() {
widget.tabindex = i;
});
},
child: Text(tabTitles[i]),
),
));
}
return btnList;
}
List<List<Widget>> createTabs(tabNum) {
List<List<Widget>> tabList = [];
for (int i = 0; i < tabNum; i++) {
List<Widget> tabContent = [
Align(
alignment: Alignment.centerLeft,
child: Text(
tabTitles[i] + " Items",
),
),
...createCheckBoxList(widget.controlNum, tabTitles[i])
];
tabList.add(tabContent);
}
return tabList;
}
List<Widget> createCheckBoxList(controlNum, tabTitle) {
List<Widget> CBList = [];
for (int i = 0; i < controlNum; i++) {
String checkBoxName = '${tabTitle} Item $i';
CBList.add(CheckboxListTile(
title: Text('${tabTitle} Item $i'),
value: widget.checkBoxInfo.isChecked(checkBoxName),
onChanged: (newValue) {
setState(() {
widget.checkBoxInfo.setCheckBox(checkBoxName, newValue!);
});
}));
}
return CBList;
}
List<String> createTabTitles(tabNum) {
List<String> tabTitles = [];
for (int i = 0; i < tabNum; i++) {
tabTitles.add("A" + i.toString());
}
return tabTitles;
}
}
class CheckBoxInfo extends ChangeNotifier {
Map<String, bool> checkBoxState = {};
int checked = 0;
bool disposed = false;
void setCheckBox(String name, bool state) {
checkBoxState[name] = state;
checkChecked();
notifyListeners();
}
bool isChecked(String name) {
return checkBoxState[name]!;
}
void initCheckBox(int controlNum, int tabNum, List<String> tabTitles) {
for (int i = 0; i < tabNum; i++) {
String checkBoxName = '${tabTitles[i]} ';
for (int i = 0; i < controlNum; i++) {
setCheckBox(checkBoxName + 'Item $i', false);
}
}
}
void checkChecked() {
int _checked = 0;
checkBoxState.forEach((key, value) {
_checked += value == true ? 1 : 0;
});
checked = _checked;
}
}
itemList.dart
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:loginpage/pages/tabPage.dart';
import 'dart:developer';
import 'package:provider/provider.dart';
import 'home.dart';
class ItemList extends StatefulWidget {
ItemList({Key? key, required this.checkBoxInfo}) : super(key: key);
final CheckBoxInfo checkBoxInfo;
#override
State<StatefulWidget> createState() => ItemListState();
}
class ItemListState extends State<ItemList> {
List<Widget> itemList = [];
#override
void initState() {
super.initState();
itemList = setItemList(widget.checkBoxInfo);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Item List"),
leading: IconButton(
onPressed: () {
//Back to Home Page
Navigator.pop(context);
},
icon: Image.asset('assets/images/backbtn.png'),
),
),
body: SafeArea(
child: Container(
child: ChangeNotifierProvider(
create: (context) => widget.checkBoxInfo,
child: Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return Column(
children: itemList,
);
},
),
))),
);
}
List<Widget> setItemList(CheckBoxInfo checkBoxInfo) {
List<Widget> tempItemList = [];
checkBoxInfo.checkBoxState.forEach((key, value) {
if (checkBoxInfo.checkBoxState[key]!) {
tempItemList.add(Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
),
child: Padding(
padding: EdgeInsets.all(8),
child: Row(
children: [
Text(
key,
overflow: TextOverflow.ellipsis,
),
SizedBox(
width: 20,
),
Icon(value ? Icons.check : Icons.cancel_outlined)
],
),
),
));
}
});
return tempItemList;
}
}
THe error is the following: A CheckBoxInfo was used after being disposed.
I dont know why it doesnt work, and according to my senior, the provider should work sort of like the local storage in web.
I think there is all sorts of things going wrong here.
You create your TabPage widget on the fly, and you put your state - checkBoxInfo - in it. And then you expose it through ChangeNotifierProvider. After that you add the TabPage to the Widget tree - which will eventually create it's state object...
As soon as you navigate from the page that shows your TabPage, it's state object and the widget itself will be disposed. And your ChangeNotifierProvider is gone, too.
The thing is: it's not your ChangeNotifierProvider that is holding your state, it is the widget underneath it.
Edit: here's the code that should work. I commented out some navigation (Login Page etc.) to make it work.
In the code, ChangeNotifierProvider is above the MaterialApp - making sure it is visible in all pages you try to navigate to.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<CheckBoxInfo>(
create: (context) => CheckBoxInfo(3, 10), //tabPage!.checkBoxInfo,
child: MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: HomePage(),
),
),
));
}
}
class HomePage extends StatelessWidget {
HomePage({Key? key}) : super(key: key);
final _tabKey = GlobalKey<TabPageState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Home Page"),
leading: IconButton(
onPressed: () {
//Back to Login Page
// Navigator.push(
// context, MaterialPageRoute(builder: (context) => LoginPage()));
},
icon: const Icon(Icons.arrow_back), //.asset('assets/images/backbtn.png'),
),
actions: [
Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return IconButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const ItemList()));
},
icon: const Icon(Icons.shopping_cart),
);
},
),
]),
body: SafeArea(
child: Scaffold(
body: Center(
child: Column(
children: <Widget>[
const SizedBox(height: 30),
const Text('This is the Home Page'),
const SizedBox(height: 20),
const Text("Test"),
//Tab Page
Consumer<CheckBoxInfo>(builder: (context, checkBoxInfo, child) {
return TabPage(key: _tabKey, tabNum: checkBoxInfo.tabNum, controlNum: checkBoxInfo.controlNum);
}),
TextButton(
onPressed: () {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => MobileList(data: data)));
},
child: const Text("Mobile List")),
],
),
),
),
),
floatingActionButton: Container(
decoration: BoxDecoration(color: Colors.grey[800], shape: BoxShape.circle),
child: IconButton(
color: Colors.lightBlue,
onPressed: () {
_tabKey.currentState!.scrollToOffset(100, const Duration(milliseconds: 200));
},
icon: const Icon(Icons.ac_unit_outlined)),
),
);
}
}
class TabPage extends StatefulWidget {
const TabPage({Key? key, required this.tabNum, required this.controlNum}) : super(key: key);
final int controlNum;
final int tabNum;
#override
State<StatefulWidget> createState() => TabPageState();
}
class TabPageState extends State<TabPage> {
List<List<Widget>> tabs = [];
ScrollController? _scrollController;
int tabindex = 0;
void scrollToOffset(increment, duration) {
_scrollController!.animateTo(_scrollController!.offset + increment, duration: duration, curve: Curves.ease);
}
void tabSetState() {
setState(() {});
}
#override
void initState() {
super.initState();
_scrollController = ScrollController(initialScrollOffset: 20);
_scrollController!.addListener(() {
print(_scrollController!.offset);
});
}
#override
Widget build(BuildContext context) {
var checkBoxInfo = Provider.of<CheckBoxInfo>(context, listen: false);
tabs = createTabs(checkBoxInfo);
return SafeArea(
child: Column(
children: [
const SizedBox(
height: 10,
),
Container(
margin: const EdgeInsets.only(left: 20.0, right: 20.0),
decoration: BoxDecoration(border: Border.all(width: 3, color: Colors.black)),
child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _scrollController,
child: Row(
children: createTabBtns(checkBoxInfo.tabTitles),
),
),
Padding(
padding: const EdgeInsets.all(5),
child: Column(
children: tabs[tabindex],
),
)
]),
),
],
),
);
}
List<Widget> createTabBtns(List<String> tabTitles) {
List<Widget> btnList = [];
for (int i = 0; i < widget.tabNum; i++) {
btnList.add(Container(
decoration: BoxDecoration(
border: Border(
right: const BorderSide(width: 1, color: Colors.grey),
bottom: tabindex == i
? BorderSide(width: 4, color: Colors.blue[400]!)
: BorderSide(width: 4, color: Colors.grey[400]!))),
child: TextButton(
onPressed: () {
setState(() {
tabindex = i;
});
},
child: Text(tabTitles[i]),
),
));
}
return btnList;
}
List<List<Widget>> createTabs(CheckBoxInfo checkBoxInfo) {
List<List<Widget>> tabList = [];
for (int i = 0; i < widget.tabNum; i++) {
List<Widget> tabContent = [
Align(
alignment: Alignment.centerLeft,
child: Text(
checkBoxInfo.tabTitles[i] + " Items",
),
),
...createCheckBoxList(checkBoxInfo, checkBoxInfo.tabTitles[i])
];
tabList.add(tabContent);
}
return tabList;
}
List<Widget> createCheckBoxList(checkBoxInfo, tabTitle) {
List<Widget> cBList = [];
for (int i = 0; i < widget.controlNum; i++) {
String checkBoxName = '$tabTitle Item $i';
cBList.add(CheckboxListTile(
title: Text('$tabTitle Item $i'),
value: checkBoxInfo.isChecked(checkBoxName),
onChanged: (newValue) {
setState(() {
checkBoxInfo.setCheckBox(checkBoxName, newValue!);
});
}));
}
return cBList;
}
}
class CheckBoxInfo extends ChangeNotifier {
Map<String, bool> checkBoxState = {};
int checked = 0;
// bool disposed = false;
List<String> tabTitles = [];
int controlNum;
int tabNum;
CheckBoxInfo(this.controlNum, this.tabNum) {
for (int i = 0; i < tabNum; i++) {
String tabTitle = "A" + i.toString();
tabTitles.add(tabTitle);
for (int i = 0; i < controlNum; i++) {
setCheckBox(tabTitle + ' Item $i', false);
}
}
}
void setCheckBox(String name, bool state) {
checkBoxState[name] = state;
checkChecked();
notifyListeners();
}
bool isChecked(String name) {
return checkBoxState[name]!;
}
void checkChecked() {
int _checked = 0;
checkBoxState.forEach((key, value) {
_checked += value == true ? 1 : 0;
});
checked = _checked;
}
}
class ItemList extends StatelessWidget {
const ItemList({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
var checkBoxInfo = Provider.of<CheckBoxInfo>(context, listen: false);
var itemList = setItemList(checkBoxInfo);
return Scaffold(
appBar: AppBar(
title: const Text("Item List"),
leading: IconButton(
onPressed: () {
//Back to Home Page
Navigator.pop(context);
},
icon: const Icon(Icons.arrow_back),
),
),
body: SafeArea(
child: Consumer<CheckBoxInfo>(
builder: (context, checkBoxInfo, child) {
return Column(
children: itemList,
);
},
),
));
}
List<Widget> setItemList(CheckBoxInfo checkBoxInfo) {
List<Widget> tempItemList = [];
checkBoxInfo.checkBoxState.forEach((key, value) {
if (value) {
tempItemList.add(Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
),
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
children: [
Text(
key,
overflow: TextOverflow.ellipsis,
),
const SizedBox(
width: 20,
),
Icon(value ? Icons.check : Icons.cancel_outlined)
],
),
),
));
}
});
return tempItemList;
}
}
#override
void dispose() {
_disposed = true;
super.dispose();
}
#override
void notifyListeners() {
if (!_disposed) {
super.notifyListeners();
}
}
I'm new to flutter and I'm trying to get the countdown-variable from the SetTimerPage to the CupertinoTimePickerButton-Page. Then change it there to the chosen time and give it back. Next I want to give the changed countdown to the next page where a countdown animation starts. I'm also open for suggestions to improve my syntax. Thank you :)
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.red,
),
home: SetTimerPage(),
);
}
}
class SetTimerPage extends StatefulWidget {
#override
_SetTimerPageState createState() => _SetTimerPageState();
}
class _SetTimerPageState extends State<SetTimerPage> {
final Duration countdown = Duration(minutes: 0, seconds: 0);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('RoundONE'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CustomRowWidget(
icon: Icons.alarm_sharp,
text: 'COUNTDOWN',
button: CupertinoTimePickerButton(passedValue: countdown),
),
StartButton(countdown: countdown),
],
),
),
);
}
}
class CupertinoTimePickerButton extends StatefulWidget {
Duration passedValue;
CupertinoTimePickerButton({
Key key,
#required this.passedValue,
}) : super(key: key);
#override
_CupertinoTimePickerButtonState createState() =>
_CupertinoTimePickerButtonState();
}
class _CupertinoTimePickerButtonState extends State<CupertinoTimePickerButton> {
#override
Widget build(BuildContext context) {
return MaterialButton(
child: Text(
_formatDuration(widget.passedValue),
style: TextStyle(color: Colors.white),
),
color: Colors.redAccent,
onPressed: () {
_cupertinoTimeSetter(context);
},
);
}
Future _cupertinoTimeSetter(BuildContext context) {
return showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height / 2,
child: CupertinoTimerPicker(
onTimerDurationChanged: (Duration newDuration) {
setState(() {
widget.passedValue = newDuration;
});
},
minuteInterval: 1,
secondInterval: 5,
mode: CupertinoTimerPickerMode.ms,
),
);
},
);
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "$twoDigitMinutes:$twoDigitSeconds";
}
}
The best way is to use a call back that will give back the value to it's parent and for this case you can use ValueChanged. Then after the parent will be incharged to change the variable value.
class SetTimerPage extends StatefulWidget {
#override
_SetTimerPageState createState() => _SetTimerPageState();
}
class _SetTimerPageState extends State<SetTimerPage> {
Duration countdown;
#override
void initState() {
super.initState();
countdown = Duration(minutes: 0, seconds: 0);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('RoundONE'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CustomRowWidget(
icon: Icons.alarm_sharp,
text: 'COUNTDOWN',
button: CupertinoTimePickerButton(
passedValue: countdown,
onChanged: (Duration duration) {
setState(() {
this.countdown = duration;
});
},
),
),
StartButton(countdown: countdown),
],
),
),
);
}
}
class CupertinoTimePickerButton extends StatelessWidget {
final Duration passedValue;
final ValueChanged<Duration> onChanged;
#override
Widget build(BuildContext context) {
return MaterialButton(
child: Text(
_formatDuration(widget.passedValue),
style: TextStyle(color: Colors.white),
),
color: Colors.redAccent,
onPressed: () {
_cupertinoTimeSetter(context);
},
);
}
Future _cupertinoTimeSetter(BuildContext context) {
return showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height / 2,
child: CupertinoTimerPicker(
onTimerDurationChanged: this.onChanged,
minuteInterval: 1,
secondInterval: 5,
mode: CupertinoTimerPickerMode.ms,
),
);
},
);
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "$twoDigitMinutes:$twoDigitSeconds";
}
}
I'm trying to make a clicker-like app to test myself. Everything was perfect until I came to async thing. The thing I want to do is a program that multiplies itself by it's house numbers. Like, user if user has 2 home, user should earn 2 points per second. I read the original documentation of dart and made it from copying there.
Code:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:async/async.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Zikirmatik'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
int _max = 0;
int _ev = 0;
int _toplanan = 0;
void _incrementCounter() {// Eklemeler sürekli tekrar çağrıldığı için bunları ayrı bir voide almamız gerek
setState(() { //Tekrar çağrılmasını sağlayan komut
_counter++;
});
}
void _decreaseCounter(){
setState(() {
_counter--;
});
}
void _resetCounter(){
setState(() {
_counter = 0;
});
}
void _evArttiran(){
setState(() {
_ev++;
});
}
void _otoArttiran(){
setState(() {
_toplanan = _ev * 1;
});
}
#override
Widget build(BuildContext context) {
if(_counter > _max){ //Yüksek skor if'i
_max = _counter;
}
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Skor:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1, // Anlık skoru kalın göstern
),
Text(
'Yüksek Skor:',
),
Text(
'$_max',
),
Text(
'Ev Sayısı:',
),
Text(
'$_ev',
),
OutlineButton( // Büyük button
onPressed: () => _incrementCounter(), // Ayrı bi void yazmamak için fat işaret kullanıyoruz
child: Container(
width: 1000, // Ayarlamazsanız küçük oluyor
height: 500,
child: Icon(Icons.add, size:100)
)
)
],
),
),
floatingActionButton: Row( //Yan yana düğme yazmak için Row gerek
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton( //Düz ufak butonlar
onPressed: _evArttiran,
child: Icon(Icons.home),
),
],
)
);
}
main() async{
Timer(Duration(seconds: 1), () {
_otoArttiran;
debugPrint(_toplanan.toString());
_counter += _toplanan;
});
}
}
You need to create a periodic timer and don't forget to put () after _otoArttiran inside the timer callback:
main() async{
Timer.periodic(Duration(seconds: 1), (_) {
_otoArttiran();
debugPrint(_toplanan.toString());
_counter += _toplanan;
});
}
You need to call this function in order for the timer to start working, so let's add initState method to your _MyHomePageState:
#override void initState() {
super.initState();
main();
}
Done!
So here is the complete code:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new TheApp());
class TheApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Zikirmatik'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
int _max = 0;
int _ev = 0;
int _toplanan = 0;
#override void initState() {
super.initState();
main();
}
void _incrementCounter() {// Eklemeler sürekli tekrar çağrıldığı için bunları ayrı bir voide almamız gerek
setState(() { //Tekrar çağrılmasını sağlayan komut
_counter++;
});
}
void _decreaseCounter(){
setState(() {
_counter--;
});
}
void _resetCounter(){
setState(() {
_counter = 0;
});
}
void _evArttiran(){
setState(() {
_ev++;
});
}
void _otoArttiran(){
setState(() {
_toplanan = _ev * 1;
});
}
#override
Widget build(BuildContext context) {
if(_counter > _max){ //Yüksek skor if'i
_max = _counter;
}
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Skor:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1, // Anlık skoru kalın göstern
),
Text(
'Yüksek Skor:',
),
Text(
'$_max',
),
Text(
'Ev Sayısı:',
),
Text(
'$_ev',
),
OutlineButton( // Büyük button
onPressed: () => _incrementCounter(), // Ayrı bi void yazmamak için fat işaret kullanıyoruz
child: Container(
width: 1000, // Ayarlamazsanız küçük oluyor
height: 500,
child: Icon(Icons.add, size:100)
)
)
],
),
),
floatingActionButton: Row( //Yan yana düğme yazmak için Row gerek
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton( //Düz ufak butonlar
onPressed: _evArttiran,
child: Icon(Icons.home),
),
],
)
);
}
main() async{
Timer.periodic(Duration(seconds: 1), (_) {
_otoArttiran();
debugPrint(_toplanan.toString());
_counter += _toplanan;
});
}
}
I'm not sure if i understood correctly but maybe you can to try something like this:
(inside _MyHomePageState)
#override
void initState() {
super.initState();
Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
_counter = _counter + _ev;
});
});
}