I have page where build ListView with CupertinoSwitch.
class NewsPageRegistr extends StatefulWidget {
NewsPageRegistr({Key key, this.model}) : super(key: key);
RegistrationModel model;
#override
_NewsPageRegistrState createState() => _NewsPageRegistrState();
}
class _NewsPageRegistrState extends State<NewsPageRegistr>
with AutomaticKeepAliveClientMixin<NewsPageRegistr> {
#override
bool get wantKeepAlive => true;
var responseV;
List<DigitalNews> digitalNews = [];
#override
void dispose() {
super.dispose();
}
#override
void initState() {
fitchData();
super.initState();
}
fitchData() async {
responseV = await apiRegistrationDataList(DropMenuMode.news);
for (var values in responseV) {
digitalNews.add(DigitalNews.fromJson(values));
}
}
#override
Widget build(BuildContext context) {
super.build(context);
return SingleChildScrollView(
child: SafeArea(
minimum: const EdgeInsets.fromLTRB(25, 0, 25, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(
width: 400,
height: 85,
child: Text(
"Ich möchte folgende Newsletter abonnieren",
textAlign: TextAlign.left,
style: GeneralStyles.titleStyle,
),
),
ListView.builder(
//padding: const EdgeInsets.symmetric(vertical: 8),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: digitalNews.length,
itemBuilder: (context, index) {
return CheckWidget(
title: digitalNews[index].displayName,
subtitle: digitalNews[index].displayDescription,
registrationName: digitalNews[index].name,
index: index,
model: widget.model,
);
}),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: GeneralStyles.petrolColor,
),
onPressed: () {
setState(() {});
widget.model.setCurrentPage(2);
},
child: const Text(
"Weiter",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w300,
fontFamily: 'FiraSans'),
)),
],
),
),
],
),
),
],
),
),
);
}
}
I use AutomaticKeepAliveClientMixin but it not working when i jump to next page (on PageView).
I add AutomaticKeepAliveClientMixin on main widget when call PageView, add to CheckWidget and to NewsPageRegistr widget but it not working. when i jump to other page on PageView List NewsPageRegistr state is dispose.
Code of widget:
class CheckWidget extends StatefulWidget {
RegistrationModel model;
bool checker = false;
final Function(String) onChanged;
final String title;
final String subtitle;
final String registrationName;
final int index;
CheckWidget({Key key, this.onChanged, this.title, this.subtitle, this.registrationName, this.index,this.model}) : super(key: key);
#override
State<CheckWidget> createState() => _CheckWidgetState();
}
class _CheckWidgetState extends State<CheckWidget> {
#override
Widget build(BuildContext context) {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Transform.scale(
alignment: Alignment.centerLeft,
scale: 0.8,
child: CupertinoSwitch(
value: widget.checker,
activeColor: GeneralStyles.petrolColor,
onChanged: (bool value) {
setState(() {
widget.checker = value;
if(value == true) {
widget.model.newsPapers[widget.index] = widget.registrationName;
}else {
widget.model.newsPapers[widget.index] = '';
}
});
},
),
),
Expanded(
child: GestureDetector(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(widget.title.replaceFirst("Newsletter", "").trim(), style:TextStyle(
color: GeneralStyles.blackColor,
fontSize: 15,
fontFamily: 'FiraSans',
fontWeight: FontWeight.w400,
)),
Text(widget.subtitle, style:TextStyle(
color: GeneralStyles.blackColor,
fontSize: 13,
fontFamily: 'FiraSans',
fontWeight: FontWeight.w300,
)),
],
),
onTap: (){
setState(() {
if(widget.checker == false) {
widget.checker = true;
widget.model.newsPapers[widget.index] = widget.registrationName;
}else {
widget.checker = false;
widget.model.newsPapers[widget.index] = '';
}
});
},
),
),
]
),
);
}
}
Related
My code works fine last week, then when the credentials expire, i recreate another credentials and replace the credentials, now the code doesnt work anymore and show the error
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: LateInitializationError: Field 'dialogflow' has not been initialized.
import 'package:dialogflow_grpc/dialogflow_grpc.dart';
import 'package:dialogflow_grpc/generated/google/cloud/dialogflow/v2beta1/session.pb.dart';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Chat extends StatefulWidget {
Chat({Key? key}) : super(key: key);
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
final List<ChatMessage> _messages = <ChatMessage>[];
final TextEditingController _textController = TextEditingController();
late DialogflowGrpcV2Beta1 dialogflow;
#override
void initState() {
super.initState();
initPlugin();
}
Future<void> initPlugin()async{
final serviceAccount = ServiceAccount.fromString(
'${(await rootBundle.loadString('assets/credentials2.json'))}');
// Create a DialogflowGrpc Instance
dialogflow = DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
}
void handleSubmitted(text) async {
print(text);
_textController.clear();
ChatMessage message = ChatMessage(
text: text,
name: "You",
type: true,
);
setState(() {
_messages.insert(0, message);
});
DetectIntentResponse data = await dialogflow.detectIntent(text, 'en-US');
String fulfillmentText = data.queryResult.fulfillmentText;
if(fulfillmentText.isNotEmpty) {
ChatMessage botMessage = ChatMessage(
text: fulfillmentText,
name: "Bot",
type: false,
);
setState(() {
_messages.insert(0, botMessage);
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Chatbot Page'),
),
body: Column(children: <Widget>[
Flexible(
child: ListView.builder(
padding: EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
)),
Divider(height: 1.0),
Container(
decoration: BoxDecoration(color: Theme.of(context).cardColor),
child: IconTheme(
data: IconThemeData(color: Theme.of(context).accentColor),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: <Widget>[
Flexible(
child: TextField(
controller: _textController,
onSubmitted: handleSubmitted,
decoration: InputDecoration.collapsed(hintText: "Send a message to begin"),
),
),
Container(
margin: EdgeInsets.symmetric(horizontal: 4.0),
child: IconButton(
icon: Icon(Icons.send),
onPressed: () => handleSubmitted(_textController.text),
),
),
],
),
),
)
),
]),
);
}
}
class ChatMessage extends StatelessWidget {
ChatMessage({required this.text, required this.name, required this.type});
final String text;
final String name;
final bool type;
List<Widget> otherMessage(context) {
return <Widget>[
new Container(
margin: const EdgeInsets.only(right: 16.0),
child: CircleAvatar(child: new Text('B')),
),
new Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(this.name,
style: TextStyle(fontWeight: FontWeight.bold)),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
];
}
List<Widget> myMessage(context) {
return <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(this.name, style: Theme.of(context).textTheme.subtitle1),
Container(
margin: const EdgeInsets.only(top: 5.0),
child: Text(text),
),
],
),
),
Container(
margin: const EdgeInsets.only(left: 16.0),
child: CircleAvatar(
child: Text(
this.name[0],
style: TextStyle(fontWeight: FontWeight.bold),
)),
),
];
}
#override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: this.type ? myMessage(context) : otherMessage(context),
),
);
}
}
initPlugin is a future method, It will take some frame to initialize the dialogflow. You can make it nullable instead of using late,
DialogflowGrpcV2Beta1? dialogflow;
Now the place where you will use, you can do a null check.
Also a better way of doing this using FutureBuilder.
Future<DialogflowGrpcV2Beta?> initPlugin()async{
final serviceAccount = ServiceAccount.fromString(
'${(await rootBundle.loadString('assets/credentials2.json'))}');
// Create a DialogflowGrpc Instance
return DialogflowGrpcV2Beta1.viaServiceAccount(serviceAccount);
}
late final Future<DialogflowGrpcV2Beta> dialogflowFuture = initPlugin();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future:dialogflowFuture,
builder: (context, snapshot) {
if(snapshot.hasError) return Text("Got Error");
if (snapshot.hasData){
final dialogflow = snapshot.data;
return Column(children: <Widget>[...
}
return CircularProgressIndicator(); //last
More about using FutureBuilder
You can make nullable instead of using late.
DialogflowGrpcV2Beta1? dialogflow;
Try it, This one will work for you.
The app only shows listview but doesn't filter any data.
If I type anything in searchbar the list view remains same
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => new _HomeState();
}
class _HomeState extends State<Home> {
Future<List> getData() async {
final response =
await http.get(Uri.parse("http://192.168.0.166/api/conn2.php"));
return json.decode(response.body);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("MY APP"),
),
body: Center(child: ListSearch()));
}
}
class ListSearch extends StatefulWidget {
ListSearchState createState() => ListSearchState();
}
class ListSearchState extends State<ListSearch> {
TextEditingController _textController = TextEditingController();
List newList = [];
onItemChanged(String value) {
setState(() {
newList = MyStatelessWidget(
list: [],
)
.list
.where((string) => string.toLowerCase().contains(value.toLowerCase()))
.toList(); //copying api data into newList
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: "Search here....",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
prefixIcon: Icon(Icons.search),
suffixIcon: IconButton(
onPressed: _textController.clear,
icon: Icon(Icons.clear),
),
),
onChanged: onItemChanged, //onItemChanged() called here
),
),
Expanded(
child: new FutureBuilder<List>(
future: _HomeState().getData(),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? new MyStatelessWidget(
list: snapshot.data ?? [],
)
: new Center(
child: CircularProgressIndicator(),
);
},
),
)
],
),
);
}
}
The database contains 'Articles','Features', 'Features2','Description' table
class _ArticleDescription extends StatelessWidget {
const _ArticleDescription({
Key? key,
required this.articles,
required this.features,
required this.features2,
//required this.description,
}) : super(key: key);
final String articles;
final String features;
final String features2;
// final String description;
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
articles,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
const Padding(padding: EdgeInsets.only(bottom: 2.0)),
Text(
features,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
],
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Text(
features2,
style: const TextStyle(
fontSize: 12.0,
color: Colors.black87,
),
),
/*Text(
description,
style: const TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),*/
],
),
),
],
);
}
}
Custom list view
class CustomListItemTwo extends StatelessWidget {
const CustomListItemTwo({
Key? key,
required this.thumbnail,
required this.articles,
required this.features,
required this.features2,
// required this.description,
}) : super(key: key);
final Widget thumbnail;
final String articles;
final String features;
final String features2;
//final String description;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: SizedBox(
height: 80,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: 0.8,
child: thumbnail,
),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 0.0, 2.0,0.0),
child: _ArticleDescription(
articles: articles,
features: features,
features2: features2,
// description: description,
),
),
)
],
),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
final List list;
//final List<String> list;
const MyStatelessWidget({ required this.list});
//const MyStatelessWidget({Key? key, required this.list}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list == null ? 0 : list.length,
itemBuilder: (context, i) {
return Container(
padding: const EdgeInsets.all(10.0),
child: new GestureDetector(
onTap: ()=>Navigator.of(context).push(
new MaterialPageRoute(
builder: (BuildContext context)=> new Detail(list:list , index: i,)
)
),
child:Column(
children:<Widget> [
CustomListItemTwo(
thumbnail: Container(
decoration: const BoxDecoration(color: Colors.blue),
),
articles: (list[i]['Articles']),
features: (list[i]['Features']),
features2: (list[i]['Features2']),
//description: (list[i]['Description']),
),
],
),
),
);
}
);
}
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: list == null ? 0 : list.length,
....
To
#override
Widget build(BuildContext context) {
var activeList = searchlist ;
//create isSearchBar bool var. and change
//true if search is Active
//false if search is inActive
isSearchBar
? activeList = searchlist
: activeList = list;
return ListView.builder(
itemCount: activeList == null ? 0 : activeList.length,
....
articles: (activeList[i]['Articles']),
....
I created a provider using the provider package that tells if an item on the BottomNavigationBar is pressed, so that the page displayed matches the item from the BottomNavigationBar on the body properties of the Scaffold. I've made a screen with TextFormField and FlatButton on the first BottomNavigationBar item. what I want to do is, I want to add all the data that has been entered in TextFromField to the third screen item from the BottomNavigationBar that I have created, and then display the third item page from the BottomNavigationBar that was added to the data through FlatButton on first screen.
I have been searching for solutions to this problem for days, but I also haven't found the answer.
My provider for BottomNavigationBar
import 'package:flutter/material.dart';
class Index with ChangeNotifier {
int _currentindex = 0;
get currentindex => _currentindex;
set currentindex(int index){
_currentindex = index;
notifyListeners();
}
}
My Scaffold
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/View/bignote_screen.dart';
import 'package:kakeiboo/View/daily_screen.dart';
import 'package:provider/provider.dart';
import 'package:kakeiboo/controller/notifier.dart';
import 'package:kakeiboo/constant.dart';
class BottomNavigate extends StatefulWidget {
#override
_BottomNavigateState createState() => _BottomNavigateState();
}
class _BottomNavigateState extends State<BottomNavigate> {
var currentTab = [
BigNotePage(),
DailyExpensesPage(),
BalancePage(),
];
#override
Widget build(BuildContext context) {
var provider = Provider.of<Index>(context);
return Scaffold(
resizeToAvoidBottomInset: false,
body: currentTab[provider.currentindex],
bottomNavigationBar: BottomNavigationBar(
onTap: (index) {
provider.currentindex = index;
},
currentIndex: provider.currentindex,
backgroundColor: Color(0xff2196f3),
showUnselectedLabels: false,
selectedItemColor: Color(0xffffffff),
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: Text(
'Big Note',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.receipt),
title: Text(
'Daily',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
title: Text(
'Balance',
style: kBottomNavigateStyle,
),
),
],
),
);
}
}
My First Screen
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/constant.dart';
class BigNotePage extends StatefulWidget {
#override
_BigNotePageState createState() => _BigNotePageState();
}
class _BigNotePageState extends State<BigNotePage> {
bool _validate = false;
final _formKey = GlobalKey<FormState>();
final _incomeController = TextEditingController();
final _expensesController = TextEditingController();
final _savingsController = TextEditingController();
#override
void dispose() {
_incomeController.dispose();
_expensesController.dispose();
_savingsController.dispose();
super.dispose();
}
void cek() {
String income = _incomeController.text;
String expenses = _expensesController.text;
String savings = _savingsController.text;
if (int.parse(income) >= int.parse(expenses) + int.parse(savings)) {
_formKey.currentState.save();
Navigator.push(context, MaterialPageRoute(builder: (context)=>BalancePage()));
} else {
setState(() {
_validate = true;
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Big Note'),
Expanded(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TxtField(
controler: _incomeController,
label: 'Income',
),
TxtField(
controler: _expensesController,
label: 'Expenses',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
TxtField(
controler: _savingsController,
label: 'Savings',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14.0),
onPressed: cek,
child: Text(
'WRITE THAT',
style: TextStyle(letterSpacing: 1.25),
),
color: Colors.yellow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
),
],
),
),
),
Container(
width: 250.0,
child: Text(
'*if you get another income for this mounth, input the income again.',
style: TextStyle(fontSize: 12.0),
),
),
],
),
);
}
}
class TxtField extends StatelessWidget {
TxtField({this.label, this.controler, this.error});
final String label;
final TextEditingController controler;
final String error;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: TextFormField(
controller: controler,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
errorText: error,
labelText: label,
prefix: Container(
padding: EdgeInsets.all(8.0),
child: Text(
'IDR',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
);
}
}
My Third Screen
import 'package:flutter/material.dart';
import 'package:kakeiboo/constant.dart';
class BalancePage extends StatefulWidget {
#override
_BalancePageState createState() => _BalancePageState();
}
class _BalancePageState extends State<BalancePage> {
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Balance'),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Savings',
style: TextStyle(fontSize: 24.0),
),
Row(
textBaseline: TextBaseline.alphabetic,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
children: [
Text('IDR'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'5.000.000',
style: TextStyle(
fontSize: 56.0, color: Colors.green),
),
),
],
),
],
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Budget',
style: TextStyle(fontSize: 24.0),
),
Row(
textBaseline: TextBaseline.alphabetic,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
children: [
Text('IDR'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'5.000.000',
style: TextStyle(
fontSize: 56.0, color: Colors.red),
),
),
],
),
],
),
),
],
),
),
)
],
),
);
}
}
My First Screen Look
My Third Screen Look
Because you're already using Provider I would suggest using a PageController instead of your class Index(), this is because it will do exactly the same but PageController has some other advantages (as controlling a PageView, and it's already there to avoid more boilerplate when changing page)
//Your Savings model
class MySavings{
int savings = 0;
int income = 0;
int expenses = 0;
}
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/View/bignote_screen.dart';
import 'package:kakeiboo/View/daily_screen.dart';
import 'package:provider/provider.dart';
import 'package:kakeiboo/controller/notifier.dart';
import 'package:kakeiboo/constant.dart';
//import your Savings model
class BottomNavigate extends StatefulWidget {
#override
_BottomNavigateState createState() => _BottomNavigateState();
}
class _BottomNavigateState extends State<BottomNavigate> {
PageController _pageController;
#override
void initState() {
super.initState();
_pageController = PageController();
}
#override
void dispose(){
super.dispose();
_pageController?.dispose();
}
#override
Widget build(BuildContext context) {
var provider = Provider.of<Index>(context);
return MultiProvider(
providers: [
ChangeNotifierProvider<PageController>.value(value: _pageController), //now the PageController can be seen as any other Provider
Provider<MySavings>(create: (_) => MySavings())
],
child: Scaffold(
resizeToAvoidBottomInset: false,
body: PageView(
controller: _pageController,
physics: NeverScrollableScrollPhysics(), //So the user doesn't scroll and move only when you pressed the buttons
children: <Widget>[
BigNotePage(),
DailyExpensesPage(),
BalancePage(),
],
),
bottomNavigationBar: MyBottomBar()
)
);
}
}
class MyBottomBar extends StatlessWidget{
#override
Widget build(BuildContext context){
final PageController pageController = Provider.of<PageController>(context, listen: false);
final int index = context.select<PageController, int>((pageController) => pageController.hasClients ? pageController.page.round() : pageController.initialPage);// the index the pageController currently is (if there is no client attached it uses the initialPAge that defaults to index 0)
return BottomNavigationBar(
onTap: (index) {
pageController.jumpToPage(index);
//In case you want it animated uncomment the next line and comment jumpToPage()
//pageController.animateToPage(index, duration: const Duration(milliseconds: 300), curve: Curves.ease);
},
currentIndex: index,
backgroundColor: Color(0xff2196f3),
showUnselectedLabels: false,
selectedItemColor: Color(0xffffffff),
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.book),
title: Text(
'Big Note',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.receipt),
title: Text(
'Daily',
style: kBottomNavigateStyle,
),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet),
title: Text(
'Balance',
style: kBottomNavigateStyle,
),
),
],
),
);
}
}
Now in SCREEN 1
import 'package:flutter/material.dart';
import 'package:kakeiboo/View/balance_screen.dart';
import 'package:kakeiboo/constant.dart';
//import your Savings model
class BigNotePage extends StatefulWidget {
#override
_BigNotePageState createState() => _BigNotePageState();
}
class _BigNotePageState extends State<BigNotePage> {
bool _validate = false;
final _formKey = GlobalKey<FormState>();
final _incomeController = TextEditingController();
final _expensesController = TextEditingController();
final _savingsController = TextEditingController();
#override
void dispose() {
_incomeController.dispose();
_expensesController.dispose();
_savingsController.dispose();
super.dispose();
}
void cek() {
String income = _incomeController.text;
String expenses = _expensesController.text;
String savings = _savingsController.text;
if (int.parse(income) >= int.parse(expenses) + int.parse(savings)) {
final PageController pageController = Provider.of<PageController>(context, listen: false);
final MySavings mySavings = Provider.of<MySavings>(context, listen: false);
mySavings..income = int.parse(income)..expenses = int.parse(expenses)..savings= int.parse(savings);
_formKey.currentState.save();
pageController.jumpToPage(2); //Index 2 is BalancePage
//In case you want it animated uncomment the next line and comment jumpToPage()
//pageController.animateToPage(2, duration: const Duration(milliseconds: 300), curve: Curves.ease);
} else {
setState(() {
_validate = true;
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Big Note'),
Expanded(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TxtField(
controler: _incomeController,
label: 'Income',
),
TxtField(
controler: _expensesController,
label: 'Expenses',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
TxtField(
controler: _savingsController,
label: 'Savings',
error: _validate
? 'Expenses + Savings Are More Than Income'
: null,
),
Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 14.0),
onPressed: cek,
child: Text(
'WRITE THAT',
style: TextStyle(letterSpacing: 1.25),
),
color: Colors.yellow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
),
],
),
),
),
Container(
width: 250.0,
child: Text(
'*if you get another income for this mounth, input the income again.',
style: TextStyle(fontSize: 12.0),
),
),
],
),
);
}
}
class TxtField extends StatelessWidget {
TxtField({this.label, this.controler, this.error});
final String label;
final TextEditingController controler;
final String error;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 12.0),
child: TextFormField(
controller: controler,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
errorText: error,
labelText: label,
prefix: Container(
padding: EdgeInsets.all(8.0),
child: Text(
'IDR',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
);
}
}
And finally in SCREEEN 3 you just call
final MySavings mysavings = Provider.of<MySavings>(context, listen: false);
and use its values (savings, expenses and income) to display in each Text, do some math if you want or change its value (If you want to update as soon as you change them then make MySavings a ChangeNotifier).
If you dont't want to use PageView and stick with the Index class just check the logic and change all the PageController with your index provider and it should work the same
You could save the TextFormField value to a provider property, this way it will be available on all screens
SCENARIO
I have a dummy image, under image there is price and under price there three widget
Two widget are buttons (+) and (-) and one widget is Text('1') which is a QTY.
QUESTION
When i click on the button it increment and decrement the number but how do i change the price based on QTY (if QTY is 2 then price must be double)
class Quantities extends StatefulWidget {
final productprice;
final productimage;
Quantities({this.productprice, this.productimage});
#override
_QuantitiesState createState() => _QuantitiesState(productprice,productimage);
}
class _QuantitiesState extends State<Quantities> {
int counter = 1;
final productprice;
final productimage;
_QuantitiesState(this.productprice, this.productimage);
void increment() {
setState(() {
counter++;
});
}
void decrement() {
setState(() {
counter--;
});
}
#override
Widget build(BuildContext context) {
return PlatformScaffold(
appBar: PlatformAppBar(
backgroundColor: Colors.lightBlue[900],
title: Text('Quantities'),
),
body: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: ListView(
children: <Widget>[
new Container(
height: 200.0,
child: GridTile(
child: Container(
color: Colors.white,
child: Image.asset(productimage),),),),
Center(
child: Text(
productprice,),),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: PlatformButton(
onPressed: () {
decrement();
if (counter < 1) {
counter = 1;
}
},
child: Text(
'-',
),
androidFlat: (_) =>
MaterialFlatButtonData(color: Colors.cyan),
ios: (_) => CupertinoButtonData(
color: Colors.cyan
)),
),
Text(
'$counter',
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: PlatformButton(
onPressed: () {
increment();
},
child: Text(
'+',
style: TextStyle(color: Colors.white, fontSize: 30.0),
),
androidFlat: (_) =>
MaterialFlatButtonData(color: Colors.cyan),
ios: (_) => CupertinoButtonData(
color: Colors.cyan
)),
this is the full code example:
import 'package:flutter/material.dart';
import 'package:project_app/proyects/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Product price',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Quantities(productimage: "",productprice: "20$",),
);
}
}
class Quantities extends StatefulWidget {
final productprice;
final productimage;
Quantities({this.productprice, this.productimage});
#override
_QuantitiesState createState() =>
_QuantitiesState(productprice, productimage);
}
class _QuantitiesState extends State<Quantities> {
int counter = 1;
final productprice;
double finalprice;
final productimage;
final productp =productprice.replaceAll(new RegExp(r'\$'), '');
_QuantitiesState(this.productprice, this.productimage);
void increment() {
setState(() {
counter++;
finalprice=double.parse(productp)*counter;
});
}
void decrement() {
setState(() {
counter--;
finalprice=double.parse(productp)*counter;
});
}
#override
void initState() {
super.initState();
finalprice= double.parse(productp);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue[900],
title: Text('Quantities'),
),
body: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: ListView(
children: <Widget>[
Center(
child: Text(
finalprice.toString(),
),
),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: FlatButton(
onPressed: () {
if (counter > 1) {
decrement();
}
},
child: Text(
'-',
),
),
),
Text(
'$counter',
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: FlatButton(
onPressed: () {
increment();
},
child: Text(
'+',
style:
TextStyle(color: Colors.white, fontSize: 30.0),
),
),
),
]),
),
],
),
));
}
}
In this case you need to multiply the value of product price in
setstate(){
productprice=productprice*counter;
}
or
productprice*=counter;
The tabs page have three tabs- Nearby,Recent and Notice tabs.
Tabs.dart-
class Tabs extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
SizedBox(width: 24),
MyTab(text: 'Nearby', isSelected: false),
MyTab(text: 'Recent', isSelected: true),
MyTab(text: 'Notice', isSelected: false),
],
);
}
}
class MyTab extends StatelessWidget {
final String text;
final bool isSelected;
const MyTab({Key key, #required this.isSelected, #required this.text})
: super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
text,
style: TextStyle(
fontSize: isSelected ? 16 : 14,
color: isSelected ? Colors.black : Colors.grey,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
),
),
Container(
height: 6,
width: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: isSelected ? Color(0xFFFF5A1D) : Colors.white,
),
)
],
),
);
}
}
In the home-page.dart file the tabs defined in tabs.dart file is called but are non-functional -
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 8),
Header(),
SizedBox(height: 40),
Tabs(),
SizedBox(height: 8),
SlidingCardsView(),
],
),
),
],
),
);
}
}
As you can see that the SlidingCardsView() is called below the tabs, but I want to open the SlidingCardsView() on clicking the recent tab and further PageOne() to Nearby and PageTwo() to notice tabs. Can anyone help me with this?.Thanks in Advance.
Here is the code, change things according to your needs further,
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Tabs(refresh: () => setState(() {})),
value == 0 ? Center(child: Text("Nearby Page", style: TextStyle(fontSize: 56))) : Container(),
value == 1 ? Center(child: Text("Recent Page", style: TextStyle(fontSize: 56))) : Container(),
value == 2 ? Center(child: Text("Notice Page", style: TextStyle(fontSize: 56))) : Container(),
],
),
),
);
}
}
class Tabs extends StatefulWidget {
final Function refresh;
Tabs({this.refresh});
#override
_TabsState createState() => _TabsState();
}
int value = 1;
class _TabsState extends State<Tabs> {
#override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
SizedBox(width: 24),
MyTab(text: 'Nearby', isSelected: value == 0, onTap: () => _updateValue(0)),
MyTab(text: 'Recent', isSelected: value == 1, onTap: () => _updateValue(1)),
MyTab(text: 'Notice', isSelected: value == 2, onTap: () => _updateValue(2)),
],
);
}
void _updateValue(int newValue) {
widget.refresh();
setState(() {
value = newValue;
});
}
}
class MyTab extends StatelessWidget {
final String text;
final bool isSelected;
final Function onTap;
const MyTab({Key key, #required this.isSelected, #required this.text, this.onTap}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
onTap: onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
text,
style: TextStyle(
fontSize: isSelected ? 16 : 14,
color: isSelected ? Colors.black : Colors.grey,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
),
),
Container(
height: 6,
width: 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: isSelected ? Color(0xFFFF5A1D) : Colors.white,
),
)
],
),
),
);
}
}