I want to create a custom calendar, like this:
How can I do this?
You can design your own custom Calendar Widget as follows
import 'package:flutter/material.dart';
class Calendar extends StatefulWidget {
#override
_CalendarState createState() => _CalendarState();
}
class _CalendarState extends State<Calendar> {
DateTime selectedDate = DateTime.now(); // TO tracking date
int currentDateSelectedIndex = 0; //For Horizontal Date
ScrollController scrollController =
ScrollController(); //To Track Scroll of ListView
List<String> listOfMonths = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
];
List<String> listOfDays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
automaticallyImplyLeading: false,
title: Text('My Calendar'),
),
body: Column(
children: [
//To Show Current Date
Container(
height: 30,
margin: EdgeInsets.only(left: 10),
alignment: Alignment.centerLeft,
child: Text(
selectedDate.day.toString() +
'-' +
listOfMonths[selectedDate.month - 1] +
', ' +
selectedDate.year.toString(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w800,
color: Colors.indigo[700]),
)),
SizedBox(height: 10),
//To show Calendar Widget
Container(
height: 80,
child: Container(
child: ListView.separated(
separatorBuilder: (BuildContext context, int index) {
return SizedBox(width: 10);
},
itemCount: 365,
controller: scrollController,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
setState(() {
currentDateSelectedIndex = index;
selectedDate =
DateTime.now().add(Duration(days: index));
});
},
child: Container(
height: 80,
width: 60,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
offset: Offset(3, 3),
blurRadius: 5)
],
color: currentDateSelectedIndex == index
? Colors.black
: Colors.white),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
listOfMonths[DateTime.now()
.add(Duration(days: index))
.month -
1]
.toString(),
style: TextStyle(
fontSize: 16,
color: currentDateSelectedIndex == index
? Colors.white
: Colors.grey),
),
SizedBox(
height: 5,
),
Text(
DateTime.now()
.add(Duration(days: index))
.day
.toString(),
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w700,
color: currentDateSelectedIndex == index
? Colors.white
: Colors.grey),
),
SizedBox(
height: 5,
),
Text(
listOfDays[DateTime.now()
.add(Duration(days: index))
.weekday -
1]
.toString(),
style: TextStyle(
fontSize: 16,
color: currentDateSelectedIndex == index
? Colors.white
: Colors.grey),
),
],
),
),
);
},
))),
],
),
));
}
}
Flutter Table Calendar
Fully Customisable as per requirement
You can copy paste run full code below
You can reference source code of package https://pub.dev/packages/calendar_timeline or directly use it
code snippet
CalendarTimeline(
initialDate: DateTime(2020, 2, 20),
firstDate: DateTime(2020, 2, 15),
lastDate: DateTime(2021, 11, 20),
onDateSelected: (date) => print(date),
leftMargin: 20,
monthColor: Colors.white70,
dayColor: Colors.teal[200],
//dayNameColor: Color(0xFF333A47),
activeDayColor: Colors.white,
activeBackgroundDayColor: Colors.redAccent[100],
dotsColor: Color(0xFF333A47),
selectableDayPredicate: (date) => date.day != 23,
),
working demo
full code
import 'package:calendar_timeline/calendar_timeline.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF333A47),
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16),
child: Text(
'Calendar Timeline',
style: Theme.of(context).textTheme.title.copyWith(color: Colors.tealAccent[100]),
),
),
CalendarTimeline(
initialDate: DateTime(2020, 2, 20),
firstDate: DateTime(2020, 2, 15),
lastDate: DateTime(2021, 11, 20),
onDateSelected: (date) => print(date),
leftMargin: 20,
monthColor: Colors.white70,
dayColor: Colors.teal[200],
//dayNameColor: Color(0xFF333A47),
activeDayColor: Colors.white,
activeBackgroundDayColor: Colors.redAccent[100],
dotsColor: Color(0xFF333A47),
selectableDayPredicate: (date) => date.day != 23,
),
],
),
),
);
}
}
Related
I ran into a snag while using the scroll_date_picker package. I succeeded in marking the scroll as shown in the figure below, but I want only the year to be displayed and scrolled, not all of the year, month, and day. How would I recommend changing _selectedDate in this case?
This is my code.
import 'package:flutter/material.dart';
import 'package:scroll_date_picker/scroll_date_picker.dart';
import 'package:shipda/constants.dart';
class BuiltYearChoice extends StatefulWidget {
const BuiltYearChoice({Key? key}) : super(key: key);
#override
State<BuiltYearChoice> createState() => _BuiltYearChoiceState();
}
class _BuiltYearChoiceState extends State<BuiltYearChoice> {
DateTime _selectedDate = DateTime.now();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: baseColor10,
elevation: 0,
leading: TextButton(
onPressed: () {},
child: Text('Reset'),
),
title: Text(
'Example',
style: titleMediumBase50(),
),
centerTitle: true,
actions: [
IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(
Icons.close,
color: baseColor50,
),
),
],
),
body: Padding(
padding: const EdgeInsets.fromLTRB(48, 16, 48, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Text(
'min',
// '최소진수년도',
style: TextStyle(
fontSize: bodyMedium,
fontFamily: 'regular',
color: Colors.grey.shade500,
),
),
marginHeight4,
Text(
'0000',
style: TextStyle(
fontSize: 32,
fontFamily: 'bold',
),
),
],
),
Column(
children: [
Text(''),
Text(
'~',
style: TextStyle(
fontSize: 32,
fontFamily: 'bold',
color: Colors.grey.shade400,
),
),
],
),
Column(
children: [
Text(
'max',
// '최대진수년도',
style: TextStyle(
fontSize: bodyMedium,
fontFamily: 'regular',
color: Colors.grey.shade500,
),
),
marginHeight4,
Text(
'0000',
style: TextStyle(
fontSize: 32,
fontFamily: 'bold',
),
),
],
),
],
),
SizedBox(
height: 300,
child: ScrollDatePicker(
locale: Locale('ko'),
selectedDate: _selectedDate,
onDateTimeChanged: (DateTime value) {
setState(() {
_selectedDate = value;
});
}),
)
],
),
),
);
}
}
You can make your CustomPicker, something like this:
import 'package:flutter/material.dart';
class CustomPicker extends StatelessWidget {
final List<DateTime> list;
const CustomPicker(this.list, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
// define item height
double itemHeight = 30;
var middleIndex = (list.length / 2).floor(); // index of the middle item
var scrollController = ScrollController(
// if you want middle item to be pre-selected
initialScrollOffset: middleIndex * itemHeight,
);
int numberOfItemsToBeVisible = 5;
double pickerHeight = itemHeight * numberOfItemsToBeVisible;
// or you can pass index of the item you want to be visible
var selectedItem = ValueNotifier(list[middleIndex]);
// changing selected item on scroll
scrollController.addListener(() {
selectedItem.value = list[(scrollController.offset / itemHeight).round()];
});
return Column(
children: [
Stack(
children: [
Positioned.fill(
child: Center(
child: Container(
height: itemHeight,
width: MediaQuery.of(context).size.width,
decoration: ShapeDecoration(
color: Colors.grey.shade300,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
),
),
),
// picker
SizedBox(
height: pickerHeight,
child: ListWheelScrollView(
diameterRatio: 1.2,
itemExtent: itemHeight,
controller: scrollController,
children: list
.map(
(element) => Align(
alignment: Alignment.center,
child: Text('${element.year}'),
),
)
.toList(),
),
),
],
),
// selected item
ValueListenableBuilder(
valueListenable: selectedItem,
builder: (context, DateTime value, _) =>
Text('selected year: ${value.year}'),
),
],
);
}
}
Then you can use it like this:
SizedBox(
height: 300,
child: CustomPicker(
List.generate(21, (index) => DateTime(2000 + index)),
),
)
The result is:
#main.dart file
import 'package:flutter/material.dart';
import './widgets/new_transaction.dart';
import './widgets/transaction_list.dart';
import './widgets/chart.dart';
import './models/tranasction.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Personal Expenses',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.amber,
// errorColor: Colors.red,
fontFamily: 'Quicksand',
textTheme: ThemeData.light().textTheme.copyWith(
titleMedium: TextStyle(
fontFamily: 'OpenSans',
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
appBarTheme: AppBarTheme(
textTheme: ThemeData.light().textTheme.copyWith(
titleMedium: TextStyle(
fontFamily: 'OpenSans',
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
)),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
// String titleInput;
// String amountInput;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<Transaction> _userTransactions = [
// Transaction(
// id: 't1',
// title: 'New Shoes',
// amount: 69.99,
// date: DateTime.now(),
// ),
// Transaction(
// id: 't2',
// title: 'Weekly Groceries',
// amount: 16.53,
// date: DateTime.now(),
// ),
];
List<Transaction> get _recentTransactions {
return _userTransactions.where((tx) {
return tx.date.isAfter(
DateTime.now().subtract(
Duration(days: 7),
),
);
}).toList();
}
void _addNewTransaction(
String txTitle, double txAmount, DateTime chosenDate) {
final newTx = Transaction(
title: txTitle,
amount: txAmount,
date: chosenDate,
id: DateTime.now().toString(),
);
setState(() {
_userTransactions.add(newTx);
});
}
void _startAddNewTransaction(BuildContext ctx) {
showModalBottomSheet(
context: ctx,
builder: (_) {
return GestureDetector(
onTap: () {},
child: NewTransaction(_addNewTransaction),
behavior: HitTestBehavior.opaque,
);
},
);
}
void _deleteTransaction(String id) {
setState(() {
_userTransactions.removeWhere((tx) => tx.id == id);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Personal Expenses',
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
],
),
body: SingleChildScrollView(
child: Column(
// mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Chart(_recentTransactions),
TransactionList(_userTransactions, _deleteTransaction),
],
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => _startAddNewTransaction(context),
),
);
}
}
#new_transaction.dart file
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:flutter/src/widgets/framework.dart';
class NewTransaction extends StatefulWidget {
final Function addTx;
NewTransaction(this.addTx);
#override
_NewTransactionState createState() => _NewTransactionState();
}
class _NewTransactionState extends State<NewTransaction> {
final _titleController = TextEditingController();
final _amountController = TextEditingController();
late DateTime _selectedDate;
void initState() {
_selectedDate:
DateTime.now();
super.initState();
}
void _submitData() {
if (_amountController.text.isEmpty) {
return;
}
final enteredTitle = _titleController.text;
final enteredAmount = double.parse(_amountController.text);
if (enteredTitle.isEmpty || enteredAmount <= 0 || _selectedDate == null) {
return;
}
widget.addTx(
enteredTitle,
enteredAmount,
_selectedDate,
);
Navigator.of(context).pop();
}
void _presentDatePicker() {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2019),
lastDate: DateTime.now(),
).then((pickedDate) {
if (pickedDate == null) {
return;
}
setState(() {
_selectedDate = pickedDate;
});
});
print('...');
}
#override
Widget build(BuildContext context) {
return Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
TextField(
decoration: InputDecoration(labelText: 'Title'),
controller: _titleController,
onSubmitted: (_) => _submitData(),
// onChanged: (val) {
// titleInput = val;
// },
),
TextField(
decoration: InputDecoration(labelText: 'Amount'),
controller: _amountController,
keyboardType: TextInputType.number,
onSubmitted: (_) => _submitData(),
// onChanged: (val) => amountInput = val,
),
Container(
height: 70,
child: Row(
children: <Widget>[
Expanded(
child: Text(
_selectedDate == null
? 'No Date Chosen!'
: 'Picked Date: ${DateFormat.yMd().format(_selectedDate)}',
),
),
FlatButton(
textColor: Theme.of(context).primaryColor,
child: Text(
'Choose Date',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
onPressed: _presentDatePicker,
),
],
),
),
RaisedButton(
child: Text('Add Transaction'),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).textTheme.button?.color,
onPressed: _submitData,
),
],
),
),
);
}
#override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
.add(DiagnosticsProperty<DateTime>('_selectedDate', _selectedDate));
}
}
#transaction_list.dart file
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../models/tranasction.dart';
class TransactionList extends StatelessWidget {
final List<Transaction> transactions;
TransactionList(
this.transactions, void Function(String id) deleteTransaction);
#override
Widget build(BuildContext context) {
return Container(
height: 300,
child: transactions.isEmpty
? Column(
children: <Widget>[
Text(
'No transactions added yet!',
style: Theme.of(context).textTheme.titleMedium,
),
SizedBox(
height: 20,
),
Container(
height: 200,
child: Image.asset(
'assets/images/waiting.png',
fit: BoxFit.cover,
)),
],
)
: ListView.builder(
itemBuilder: (ctx, index) {
return Card(
elevation: 5,
margin: EdgeInsets.symmetric(
vertical: 8,
horizontal: 5,
),
child: ListTile(
leading: CircleAvatar(
radius: 30,
child: Padding(
padding: EdgeInsets.all(6),
child: FittedBox(
child: Text('\$${transactions[index].amount}'),
),
),
),
title: Text(
transactions[index].title,
style: Theme.of(context).textTheme.titleMedium,
),
subtitle: Text(
DateFormat.yMMMd().format(transactions[index].date),
),
),
);
},
itemCount: transactions.length,
),
);
}
}
#chart.dart file
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../models/tranasction.dart';
class TransactionList extends StatelessWidget {
final List<Transaction> transactions;
TransactionList(
this.transactions, void Function(String id) deleteTransaction);
#override
Widget build(BuildContext context) {
return Container(
height: 300,
child: transactions.isEmpty
? Column(
children: <Widget>[
Text(
'No transactions added yet!',
style: Theme.of(context).textTheme.titleMedium,
),
SizedBox(
height: 20,
),
Container(
height: 200,
child: Image.asset(
'assets/images/waiting.png',
fit: BoxFit.cover,
)),
],
)
: ListView.builder(
itemBuilder: (ctx, index) {
return Card(
elevation: 5,
margin: EdgeInsets.symmetric(
vertical: 8,
horizontal: 5,
),
child: ListTile(
leading: CircleAvatar(
radius: 30,
child: Padding(
padding: EdgeInsets.all(6),
child: FittedBox(
child: Text('\$${transactions[index].amount}'),
),
),
),
title: Text(
transactions[index].title,
style: Theme.of(context).textTheme.titleMedium,
),
subtitle: Text(
DateFormat.yMMMd().format(transactions[index].date),
),
),
);
},
itemCount: transactions.length,
),
);
}
}
#chartbar.dart file
import 'package:flutter/material.dart';
class ChartBar extends StatelessWidget {
final String label;
final double spendingAmount;
final double spendingPctOfTotal;
ChartBar(this.label, this.spendingAmount, this.spendingPctOfTotal);
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Container(
height: 20,
child: FittedBox(
child: Text('\$${spendingAmount.toStringAsFixed(0)}'),
),
),
SizedBox(
height: 4,
),
Container(
height: 60,
width: 10,
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 1.0),
color: Color.fromRGBO(220, 220, 220, 1),
borderRadius: BorderRadius.circular(10),
),
),
FractionallySizedBox(
heightFactor: spendingPctOfTotal,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(10),
),
),
),
],
),
),
SizedBox(
height: 4,
),
Text(label),
],
);
}
}
#transaction.dart file
**i am using the latest version of flutter
and using android studio as emulator,
and using vs code as code editor my code has no errors,
but i keep getting this error after many attempts
i tested using real android device too but nothing changed error message:'package:flutter/src/widgets/framework.dart':failed
assertion:line4864 pos 12:'child==_child':is not true.
see also https://flutter.dev/docs/testing/errors **
I have 2 widgets ProfitDisplay() and BetListDisplay(), I want to be able to share data from a firestore query without calling the same query twice. For ProfitDisplay() I'll need at least 1 more stream. My current code queries the db twice once for each widget which is not very efficient. I tried wrapping ListView() with StreamProvider.value() but then I got an error saying it could not find the Provider.
The query is based on dates selected in the first widget in the ListView()
class DailyPage extends StatefulWidget {
const DailyPage({Key? key}) : super(key: key);
#override
_DailyPageState createState() => _DailyPageState();
}
class _DailyPageState extends State<DailyPage> {
final FirebaseAuth auth = FirebaseAuth.instance;
final DateTime now = DateTime.now();
final days = getWeekDayList;
int _currentWeekDayNameAndNum = getCurrentWeekDayInt();
final db = FirestoreService();
#override
Widget build(BuildContext context) {
int selectedDay = int.parse(days[_currentWeekDayNameAndNum]['day']);
final User? user = auth.currentUser;
DateTime startDate = DateTime(now.year, now.month, selectedDay, 00, 00);
DateTime endDate = DateTime(now.year, now.month, selectedDay, 23, 59);
return Scaffold(
backgroundColor: white.withOpacity(1),
body: ListView(
children: [
Column(
children: [
Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(color: white, boxShadow: [
BoxShadow(
color: grey.withOpacity(0.5),
spreadRadius: 4,
blurRadius: 5,
// changes position of shadow
),
]),
child: Padding(
padding: const EdgeInsets.only(
top: 10, right: 10, left: 10, bottom: 20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
"Daily Transactions",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: black),
),
],
),
const SizedBox(
height: 25,
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(days.length, (index) {
return GestureDetector(
onTap: () {
setState(() {
_currentWeekDayNameAndNum = index;
});
},
child: SizedBox(
width:
(MediaQuery.of(context).size.width - 40) /
7,
child: Column(
children: [
Text(
days[index]['label'],
style: const TextStyle(fontSize: 10),
),
const SizedBox(
height: 10,
),
Container(
width: 30,
height: 30,
decoration: BoxDecoration(
color: _currentWeekDayNameAndNum ==
index
? primary
: Colors.transparent,
shape: BoxShape.circle,
border: Border.all(
color:
_currentWeekDayNameAndNum ==
index
? primary
: black
.withOpacity(0.1))),
child: Center(
child: Text(
days[index]['day'],
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color:
_currentWeekDayNameAndNum ==
index
? white
: black),
),
),
)
],
),
),
);
}))
],
),
),
),
],
),
StreamProvider<List<BetData>>.value(
value: FirestoreService()
.streamBetDataBetweenDates(user!, startDate, endDate),
initialData: [],
child: const ProfitDisplay(),
),
const SizedBox(
height: 10,
),
StreamProvider<List<BetData>>.value(
value: FirestoreService()
.streamBetDataBetweenDates(user, startDate, endDate),
initialData: [],
child: const BetListDisplay(),
)
],
));
}
}
class _ProfitDisplayState extends State<ProfitDisplay> {
double _dailyTotal = 0;
#override
Widget build(BuildContext context) {
List betList = Provider.of<List<BetData>>(context);
double _total = 0;
for (var bet in betList) {
_total += bet.value;
}
_dailyTotal = _total;
return Container(
margin: const EdgeInsets.fromLTRB(8, 8, 8, 0),
decoration: BoxDecoration(color: white, boxShadow: [
BoxShadow(
color: grey.withOpacity(0.5),
spreadRadius: 4,
blurRadius: 5,
// changes position of shadow
),
]),
child: Container(
alignment: Alignment.center,
margin: const EdgeInsets.all(8),
child: _dailyTotal > 0
? Text(
'£ ${_dailyTotal.toString()}',
style: const TextStyle(
color: Colors.green,
fontSize: 25,
fontWeight: FontWeight.bold),
)
: Text(
'£ ${_dailyTotal.toString()}',
style: const TextStyle(
color: Colors.red,
fontSize: 25,
fontWeight: FontWeight.bold),
),
));
}
}
Not sure if it's relevant but here's FirestoreService()
class FirestoreService {
final FirebaseFirestore _db = FirebaseFirestore.instance;
/// List of bets between startDate and endData
Stream<List<BetData>> streamBetDataBetweenDates(
User user, DateTime startDate, DateTime endDate) {
var ref = _db
.collection('users/${user.uid}/bets')
.where('d', isGreaterThanOrEqualTo: startDate)
.where('d', isLessThanOrEqualTo: endDate)
.orderBy('d', descending: true);
print('this got called at ${DateTime.now()}');
return ref.snapshots().map(
(list) => list.docs.map((doc) => BetData.fromFirestore(doc)).toList());
}
}
Here I have a form like this. i want to change the value of the blue button week below when i swipe left or right of Calendar Week. What should i do guys ?. It can only changed when I clicked on the number
Here is the code I'm using:
import 'package:flutter/material.dart';
import 'package:myhumgupdate/App/Config/palette.dart';
import 'package:myhumgupdate/Widgets/dialog_loading.dart';
import 'package:myhumgupdate/giangvien/Screens/XemTKB/TKBTheoTuan/tkbtuan_viewmodel.dart';
import 'package:myhumgupdate/Widgets/calender_week.dart';
import 'package:myhumgupdate/giangvien/models/meeting.dart';
import 'package:myhumgupdate/giangvien/models/meetingdata_source.dart';
import 'package:stacked/stacked.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
class TKBTuan extends StatefulWidget {
#override
_TKBTuanState createState() => _TKBTuanState();
}
final String _customTimeLabelText = 'Tiết';
class _TKBTuanState extends State<TKBTuan> {
#override
Widget build(BuildContext context) {
return ViewModelBuilder<TKBTuanViewModel>.reactive(
onModelReady: (model) => Future.delayed(Duration.zero,
() => DialogLoading.show(context, model.getTkbTuan(model.timeNow))),
builder: (context, TKBTuanViewModel model, child) => Column(
children: [
Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(
top: 18,
),
child: CalendarWeek(
calendarController: model.calendarController,
press: (DateTime date, _, __) {
model.getTkbTuan(date);
},
),
),
),
Container(
width: 40,
height: 56,
margin: EdgeInsets.only(right: 3),
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Palette.kPrimaryColor,
),
child: Center(
child: Text(
"Week ${model.week}",
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
],
),
Expanded(
child: SfCalendar(
view: CalendarView.week,
firstDayOfWeek: 1,
maxDate: DateTime(DateTime.now().year, DateTime.now().month,
DateTime.now().day, 00, 45, 0),
minDate: DateTime(DateTime.now().year, DateTime.now().month,
DateTime.now().day, 00, 45, 0),
headerHeight: 0,
viewHeaderHeight: 0,
dataSource: MeetingDataSource(model.getDataSource),
appointmentTimeTextFormat: 'hh:mm:ss a',
appointmentBuilder: appointmentBuilder,
initialDisplayDate: DateTime(DateTime.now().year,
DateTime.now().month, DateTime.now().day, 00, 45, 0),
monthViewSettings: MonthViewSettings(showAgenda: true),
timeSlotViewSettings: TimeSlotViewSettings(
startHour: 0,
endHour: 16,
timeFormat: _customTimeLabelText + " H",
timeIntervalHeight: 70,
timeTextStyle: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
)),
// selectionDecoration: BoxDecoration(
// color: Colors.transparent,
// border: Border.all(color: Colors.red, width: 1),
// borderRadius: const BorderRadius.all(Radius.circular(4)),
// shape: BoxShape.rectangle,
// ),
),
),
],
),
viewModelBuilder: () => TKBTuanViewModel());
}
}
Widget appointmentBuilder(BuildContext context,
CalendarAppointmentDetails calendarAppointmentDetails) {
final Meeting appointment = calendarAppointmentDetails.appointments.first;
return Container(
width: calendarAppointmentDetails.bounds.width,
height: calendarAppointmentDetails.bounds.height,
// color: appointment.background,
decoration: BoxDecoration(
color: appointment.background,
border: Border.all(
color: Colors.grey,
width: 0.5,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(2.0, 0, 0, 5.0),
child: Text(
appointment.eventName,
// textAlign: TextAlign.center,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(2.0, 0, 0, 0),
child: Text(
"Phòng: ${appointment.subText}",
style: TextStyle(fontSize: 10, fontStyle: FontStyle.italic),
),
)
],
),
);
}
And if there is no way to change the value like that, what should I do and how can I change that?
In the Flutter Event Calendar, you can programmatically select the date using selectedDate property of the CalendarController.
Inside the state, initialize the calendar controller.
final CalendarController _calendarController= CalendarController();
Using onViewChanged callback of the Flutter event calendar, you can set the first date of visible dates as selected date.
child: SfCalendar(
view: CalendarView.month,
controller: _calendarController,
onViewChanged: viewChanged,
),
void viewChanged(ViewChangedDetails viewChangedDetails) {
SchedulerBinding.instance!.addPostFrameCallback((Duration duration) {
_calendarController.selectedDate = viewChangedDetails.visibleDates[0];
});
}
Wrap your Widget in GestureDetector and use onPanUpdate like this:
GestureDetector(onPanUpdate: (details) {
if (details.delta.dx > 0) {
// swiping in right direction
// update week number
}
});
I am working on a project in which i have a class which has a row that has two children. Child one contains a TabView with a child class TabViewChild in which i am generating a gridview. On the other hand child two contains a listView. So the problem is, when i click on the gridview item i am passing that item's value to a static list and passing that list to a listview of other class. But i have no idea how to change the state of that class on item clicked or how can i achieve this task in a better way as i am new to Flutter. I want that when a person click on any gridview's item that item appears in the listview simultaneously.
class ItemMenus {
int id;
String code;
String name;
String salePrice;
String photo;
String categoryName;
String percentage;
int quantity;
ItemMenus({this.id, this.code, this.name, this.salePrice, this.photo,
this.categoryName, this.percentage, this.quantity});
ItemMenus.fromJson(Map<String, dynamic> json)
:
id = int.parse(json['id']),
code = json['code'],
name = json['name'],
salePrice = json['sale_price'],
photo = json['photo'],
categoryName = json['category_name'],
percentage = json['percentage'];
#override
String toString() {
return 'ItemMenus{id: $id, code: $code, name: $name, salePrice: $salePrice, photo: $photo, categoryName: $categoryName, percentage: $percentage}';
}
}
import 'package:food_app/model/mdl_item_menus.dart';
class ItemMenuList{
List<ItemMenus> _itmMenuLst = [];
ItemMenuList._();
static final ItemMenuList instanceItmMenuLst = ItemMenuList._();
static ItemMenuList get instance => instanceItmMenuLst;
void addItem(ItemMenus im){
_itmMenuLst.add(im);
}
List<ItemMenus> get list => _itmMenuLst;
#override
String toString() {
return 'ItemMenuList{_itmMenuLst: $_itmMenuLst}';
}
}
import 'package:flutter/material.dart';
import 'package:food_app/database/tables/tbl_categories.dart';
import 'package:food_app/model/list/item_menu_list.dart';
import 'package:food_app/model/mdl_categories.dart';
import 'package:food_app/model/mdl_item_menus.dart';
import 'package:food_app/pos/tab_bar_view.dart';
class EPos extends StatefulWidget{
#override
_EPosState createState() => _EPosState();
}
class _EPosState extends State<EPos> {
final categoryDBHelper = TblCategories.categoriesInstance;
final ItemMenuList instance2 = ItemMenuList.instance;
String _orderType = 'Dine-In', _info = 'Table No. 1', _userName = 'ZiaUddin';
List<Categories> catLst = [];
List<ItemMenus> itmLst = [];
Future getCategories() async {
catLst.clear();
var categories = await categoryDBHelper.getCategories();
categories.forEach((element) {
catLst.add(Categories(
id: element['id'],
categoryName: element['category_name'],
description: element['description'],
userId: element['user_id'],
companyId: element['company_id'],
delStatus: element['del_status']));
});
catLst.forEach((element) {
print(element);
});
return catLst;
}
#override
void initState() {
// TODO: implement initState
super.initState();
// itmLst = instance2.list;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
//#region AppBar
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.15,
color: Colors.redAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
margin: EdgeInsets.fromLTRB(8, 10, 0, 0),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(20),
color: Colors.red,
),
child: Row(
children: [
Icon(
Icons.arrow_back,
color: Colors.white,
size: 25,
),
Padding(
padding: const EdgeInsets.fromLTRB(4, 8, 10, 8),
child: Text(
_orderType,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
fontFamily: 'Ubuntu',
letterSpacing: 2.0,
),
),
),
],
),
),
Container(
margin: EdgeInsets.fromLTRB(8, 10, 0, 0),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10),
color: Colors.red,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 8),
child: Text(
_info,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.amberAccent,
fontFamily: 'Ubuntu',
letterSpacing: 2.0,
),
),
),
),
Container(
margin: EdgeInsets.only(top: 15, right: 5),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(30),
color: Colors.red,
),
child: Row(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 8, 8, 8),
child: Text(
_userName,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
fontFamily: 'Ubuntu',
letterSpacing: 1.0,
),
),
),
CircleAvatar(
backgroundColor: Colors.red,
radius: MediaQuery.of(context).size.height * 0.041,
child: CircleAvatar(
radius: MediaQuery.of(context).size.height * 0.04,
backgroundImage: AssetImage('assets/user.png'),
),
),
],
),
),
],
),
),
//endregion
Expanded(
child: Row(
children: [
//# region Menu
Flexible(
flex: 1,
child: Container(
decoration: BoxDecoration(
color: Colors.yellowAccent,
shape: BoxShape.rectangle,
),
child: Column(
children: [
Expanded(
child: Container(
color: Colors.white,
child: FutureBuilder(
future: getCategories(),
builder: (context, snapShot) {
if (snapShot.connectionState ==
ConnectionState.none &&
snapShot.hasData == null) {
return Center(
child: CircularProgressIndicator());
}
return MaterialApp(
debugShowCheckedModeBanner: false,
home: DefaultTabController(
length: catLst.length,
child: Scaffold(
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize:
Size.fromHeight(kToolbarHeight),
child: Container(
height: MediaQuery.of(context)
.size
.height *
0.1,
child: TabBar(
indicatorColor:
Colors.amberAccent,
isScrollable: true,
tabs: catLst
.map<Widget>((Categories c) {
return Tab(
icon: Icon(
Icons.style,
color: Colors.amberAccent,
size: 15,
),
child: Text(
c.categoryName
.toUpperCase(),
style: TextStyle(
color: Colors.black,
fontWeight:
FontWeight.w400,
),
),
);
}).toList(),
),
),
),
body: TabBarView(
children: catLst.map((Categories c) {
return TabBarViewChild(categoryName:c.categoryName,
callback: (){
setState(() {
instance2.addItem(ItemMenus(name: c.categoryName));
itmLst = instance2.list;
print('I am Callback');
});
},);
}).toList(),
),
),
),
);
}),
),
),
],
),
),
),
//endregion
//# region OrderList
Flexible(
flex: 1,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
),
child: ListView.builder(
itemCount: itmLst.length,
itemBuilder: (context, index){
return ListTile(
title: Text(itmLst[index].name),
);
},
),
),
),
//endregion
],
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:food_app/database/tables/tbl_item_menus.dart';
import 'package:food_app/model/list/item_menu_list.dart';
import 'package:food_app/model/mdl_item_menus.dart';
import 'package:food_app/pos/new_sale.dart';
class TabBarViewChild extends StatefulWidget {
String categoryName;
VoidCallback callback;
TabBarViewChild({Key key,#required this.categoryName, this.callback}) : super(key:key);
#override
_TabBarViewChildState createState() => _TabBarViewChildState();
}
class _TabBarViewChildState extends State<TabBarViewChild> {
final ItemMenuList instance1 = ItemMenuList.instance;
List<ItemMenus> itmLst = [];
final itemMenus = TblItemMenus.itemMenusInstance;
Future getSpecificItemMenus() async{
var items = await itemMenus.getSpecificItemMenus(widget.categoryName);
itmLst.clear();
items.forEach((e) {
itmLst.add(ItemMenus(id: e['id'], categoryName: e['category_name'], code: e['code'],
name: e['name'], percentage: e['percentage'], photo: e['photo'], quantity: e['quantity'],
salePrice: e['sale_price']));
});
for (var value in itmLst) {
print(value);
}
return itmLst;
}
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.white,
child: FutureBuilder(
future: getSpecificItemMenus(),
builder: (context, snapShot) {
if (snapShot.connectionState == ConnectionState.none
&& snapShot.hasData == null) {
return Center(child: CircularProgressIndicator());
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
scrollDirection: Axis.vertical,
itemCount: itmLst.length,
itemBuilder: (context, index){
return Padding(
padding: const EdgeInsets.all(5.0),
child: InkWell(
child: Card(
elevation: 4,
color: Colors.amberAccent,
child: Center(
child: Text(
itmLst[index].name.toUpperCase(),
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.red,
fontSize: 13,
fontWeight: FontWeight.w700,
fontFamily: 'Ubuntu',
letterSpacing: 1.0,
),
),
),
),
onTap: (){
// Provider.of<ProItemMenus>(context, listen: false).addNewItemInList(ItemMenus(name: itmLst[index].name.toUpperCase()));
instance1.addItem(ItemMenus(categoryName: itmLst[index].name.toUpperCase()));
print(itmLst[index].name.toUpperCase());
},
),
);
}
);
}
),
);
}
}
So the problem now, there are two stateful widgets.
And as we are going to share the data or the state between them, basically we need to have more one stateful Widget which will the parent of them.
This term of is this problem known as State Management.
Currently there are many reknown State Management , such as Provider and Bloc. Reference.
But personally, I recommend to use Provider, which has simple Syntaxes and Concept.