Here, I am trying flutter_form_builder for the dropdown. but there is some problem when I check the validation of all fields while button clicks on the Next button. it will check the form state is valid or not. if I click on the next button it will show all the required filed it will show me dropdown also but id I am not the select value from drop-down then it needs do not redirect any other page without selecting dropdown value because there is required validation. so the issue is drop-down validation is showing but not working.
Here is code of my screen :
class _AddWalkinServiceScheduleScreenState
extends State<AddWalkinServiceScheduleScreen>
with TickerProviderStateMixin {
final GlobalKey<FormState> _formkey = GlobalKey<FormState>();
AddWalkinModel model;
bool autovalidate = false;
final TextEditingController _bspBusinessLegalAddress =
TextEditingController();
LocationResult _pickedLocation;
Map<String, dynamic> _typeValue;
AnimationController controller;
Animation<double> animation;
final TextEditingController _serviceDate = TextEditingController();
TextEditingController _serviceTime = new TextEditingController();
String _isoDate;
String addresschoice;
List<String> _imageFilesList2 = [];
List<File> _licenseImages2 = [];
bool _isFlexible = false;
String _serviceType;
List<dynamic> _type = <dynamic>[];
#override
void initState() {
super.initState();
}
Widget _builddate() {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 11),
child: Text(
"Date",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
_buildservicedate(),
],
),
);
}
Widget _buildselectAddress() {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 11),
child: Text(
"Select Address",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
),
_buildaddresschoice(),
addresschoice == "Current Location"
? _addressTextfield()
: (addresschoice == "Select from address book" ||
model.address != null)
? _addressTextfield()
: SizedBox(),
_buildServicetype()
],
),
);
}
Widget _addressTextfield() {
return TudoTextWidget(
prefixIcon: Icon(FontAwesomeIcons.mapMarkedAlt),
labelText: "Address",
hintText: "Address",
controller: _bspBusinessLegalAddress,
validator: (val) =>
Validators.validateRequired(val, "Address"),
);
}
Widget _buildServicetype() {
return FormBuilder(
autovalidate: autovalidate,
child: FormBuilderCustomField(
attribute: "Select Address",
validators: [FormBuilderValidators.required()],
formField: FormField(
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
prefixIcon: Icon(Icons.business_center),
errorText: field.errorText,
),
isEmpty: _typeValue == [],
child: new DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text("Service Type"),
isExpanded: true,
items: [
"Normal",
"Urgent",
"Emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
value: field.value,
onChanged: (value) {
field.didChange(value);
_serviceType = value;
},
),
),
);
},
)),
);
}
Widget content(BuildContext context, AddWalkinServiceDetailViewModel awsdVm) {
var colorStyles = Theming.colorstyle(context);
Orientation orientation = MediaQuery.of(context).orientation;
return Scaffold(
backgroundColor: colorStyles['primary'],
appBar: AppBar(
elevation: 0,
title: Text("Service Details"),
centerTitle: true,
),
bottomNavigationBar: Container(
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30),
label: Text('Search'),
color: colorStyles["primary"],
textColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
setState(() {
autovalidate = true;
});
if (_formkey.currentState.validate()) {
List<ServicePicture> id1Images = [];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ServiceProviderMapScreen(
addWalkinModel: model,
),
),
);
}
}
),
],
),
),
body: FadeTransition(
opacity: animation,
child: Container(
child: Form(
autovalidate: autovalidate,
key: _formkey,
child: Stack(
children: <Widget>[
SingleChildScrollView(
padding: EdgeInsets.all(16.0),
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_builddate(),
_buildflexible(),
],
),
),
)
],
),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return new StoreConnector<AppState, AddWalkinServiceDetailViewModel>(
converter: (Store<AppState> store) =>
AddWalkinServiceDetailViewModel.fromStore(store),
builder: (BuildContext context, AddWalkinServiceDetailViewModel awsdVm) =>
content(context, awsdVm),
);
}
}
You should be using FormBuilderDropdown instead. This is included in flutter_form_builder.
DropdownButtonHideUnderline(
child: FormBuilderDropdown(
name: 'dropdown'
hint: Text("Service Type"),
isExpanded: true,
items: [
"Normal",
"Urgent",
"Emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),,
),
),
Using this, the dropdown value can be extracted by calling it from the Map GlobalKey<FormState>.currentState.value using the name set earlier as the key.
_formKey.currentState.value['dropdown']
Related
I'm trying to create a custom dialogue box, where i'm passing title, text and image parameter, when i call the dialogue box, it is not display image, here is the code
this is the code of Dialogue box.
class LoginSucessDailog extends StatefulWidget {
final String title, text;
final Image img;
const LoginSucessDailog({ required this.title, required this.text,required this.img });
#override
_LoginSucessDailogState createState() => _LoginSucessDailogState();
}
class _LoginSucessDailogState extends State<LoginSucessDailog> {
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(Constants.padding),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: contentBox(context),
);
}
contentBox(context) {
return Stack(
children: <Widget>[
Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.asset(
widget.img.toString(),
width: 100,
),
Text(
widget.title,
style:GoogleFonts.montserrat(fontSize: 22, fontWeight: FontWeight.w600),
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
color: Colors.black,
),
children: <TextSpan>[
TextSpan(
text:widget.text,
style: GoogleFonts.montserrat(fontSize: 16, color: Colors.grey)),
],
),
),
),
SizedBox50(),
okay()
],
),
),
],
);
}
}
and here i'm calling it as like this
showDialog(
context: context,
builder: (BuildContext context) {
return LoginSucessDailog( text: 'Phone number doesnt exists!',
title: 'Error',
img:Image.asset("assets/img/alert.png"));
});
but it send me this error
Unable to load asset: Image(image: AssetImage(bundle: null, name: "assets/img/alert.png"), frameBuilder: null, loadingBuilder: null, alignment: Alignment.center, this.excludeFromSemantics: false, filterQuality: low)
widget.img.toString(), if i'm not converting it into string then it gives me this error
The argument type 'Image' can't be assigned to the parameter type 'String'.
please help how to solve it .
I changed the passed value and adapt the constructor dialog.
showDialog(
context: context,
builder: (BuildContext context) {
return LoginSucessDailog( text: 'Phone number doesnt exists!',
title: 'Error',
img:'assets/img/alert.png');
});
class LoginSucessDailog extends StatefulWidget {
final String title, text, img;
const LoginSucessDailog({ required this.title, required this.text,required this.img });
#override
_LoginSucessDailogState createState() => _LoginSucessDailogState();
}
class _LoginSucessDailogState extends State<LoginSucessDailog> {
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(Constants.padding),
),
elevation: 0,
backgroundColor: Colors.transparent,
child: contentBox(context),
);
}
contentBox(context) {
return Stack(
children: <Widget>[
Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.asset(
widget.img,
width: 100,
),
Text(
widget.title,
style:GoogleFonts.montserrat(fontSize: 22, fontWeight: FontWeight.w600),
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
color: Colors.black,
),
children: <TextSpan>[
TextSpan(
text:widget.text,
style: GoogleFonts.montserrat(fontSize: 16, color: Colors.grey)),
],
),
),
),
SizedBox50(),
okay()
],
),
),
],
);
}
}
I am getting the following error :
The following _TypeError was thrown building FutureBuilder(dirty, state: _FutureBuilderState#0e8bb):
type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Comparable'
When what I am trying to do is to build a Listview using FutureBuilder from a local Json and then sort the items if user taps on menu to sort :
class _ResultScreenState extends State<ResultScreen> {
List showData;
var sortedData;
bool byName = false;
bool byRating = false;
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Image(
fit: BoxFit.cover,
image: AssetImage('assets/scuba.jpg'),
),
),
Scaffold(
appBar: AppBar(
title: Text("Scuba Dive"),
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text("Sort By")),
),
PopupMenuButton<String>(
icon: Icon(
Icons.sort,
size: 32,
),
onSelected: choiceAction,
itemBuilder: (BuildContext context) {
return Constants.choices.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
)
],
),
body: Container(
constraints: BoxConstraints.expand(),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/scuba.jpg'),
colorFilter:
ColorFilter.mode(Colors.black26, BlendMode.darken),
fit: BoxFit.cover)),
child: FutureBuilder(
builder: (context, snapshot) {
showData = json.decode(snapshot.data.toString());
if (byName) {
showData.sort();
}
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Container(
padding: EdgeInsets.all(8),
margin: EdgeInsets.all(12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white70,
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 150,
maxHeight: 80,
),
child: Image(
image: AssetImage(showData[index]["image"]),
),
),
Flexible(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
showData[index]["name"].toString(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold),
),
Text("Rating : " +
showData[index]["rating"]),
],
),
),
),
],
),
],
),
);
},
itemCount: showData == null ? 0 : showData.length,
);
},
future:
DefaultAssetBundle.of(context).loadString("assets/data.json"),
),
),
)
],
);
}
void choiceAction(String choice) {
if (choice == Constants.FirstItem) {
setState(() {
byName = true;
});
} else if (choice == Constants.SecondItem) {
print("Second");
}
}
}
What could be the reason and how can I fix it?
The error comes from this line :
showData.sort();
Because json.decode does not return a Comparable. You should consider giving a type to showData (which could be a local variable) :
List<Data> showData = List<Data>.from(json.decode(snapshot.data.toString()));
I have a for Loop where articles get loaded into a Widget and I only want one to be enabled, so how can I do that?
So far I got it working, but it doesn't recognise if I pressed another Button and I am relatively new to Flutter so I don't exactly know how I can implement such a feature.
Widget for Articles
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:wiegon/icons/nuleo_icons.dart';
import 'package:wiegon/main.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:wiegon/pages/control_screen.dart';
import 'package:wiegon/widgets/widgets.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:page_transition/page_transition.dart';
class ArticleandAmount extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
leading: Builder(
builder: (BuildContext context) {
return IconButton(
icon: new SvgPicture.asset(wiegonLogo,
allowDrawingOutsideViewBox: true,
semanticsLabel: 'Wiegon Logo'),
onPressed: null,
);
},
),
title: Text(
"Artikel und Menge",
style: TextStyle(fontSize: 18, color: Color(0xffFDFEFE)),
),
backgroundColor: Color(0xff466988),
),
body: Articleamount(),
endDrawer: Enddrawer());
}
}
class Articleamount extends StatefulWidget {
#override
_ArticleamountState createState() {
return _ArticleamountState();
}
}
String displayedWeight;
String displayedTotalPrice;
String displayedPrice;
String articleID;
String unit = "";
String articleSelected = "Artikel wählen";
class _ArticleamountState extends State<Articleamount> {
final amountController = TextEditingController();
static Color disabledColor = mainColor.withOpacity(0.5);
double price = 0.0;
double inputAmount = 0;
bool isArticleSelected = false;
bool isPriceSelected = false;
Color buttonColor = disabledColor;
String totalPrice = "0";
#override
void dispose() {
// Clean up the paremeters when the widget is disposed.
unit = "";
articlesList = {};
articleSelected = "Artikel wählen";
amountController.dispose();
super.dispose();
}
Widget articleCard(
String articleName, IconData icon, double priceForArticle) {
String tempunit = articleName.split("|")[1];
String tempID = articleName.split("&")[1].split("|")[0];
articleName = articleName.split("&")[0];
return SingleChildScrollView(
child: Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(20),
),
width: 300,
height: 120,
padding: EdgeInsets.all(5),
child: MaterialButton(
child: Align(
alignment: Alignment.centerLeft,
child: Text(
articleName,
overflow: TextOverflow.fade,
style: TextStyle(fontWeight: FontWeight.bold),
)),
highlightColor: Colors.blue,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
10,
)),
elevation: 2,
onPressed: () {
articleSelected = articleName;
articleID = tempID;
setState(() {
amountController.text = "";
totalPrice = "0";
buttonColor = disabledColor;
inputAmount = 0;
unit = tempunit;
price = priceForArticle;
isArticleSelected = true;
});
},
),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(children: <Widget>[
FractionallySizedBox(
widthFactor: deviceWidth(context),
child: Center(
child: Container(
width: 600,
margin: EdgeInsets.only(top: 35),
color: Colors.transparent,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
progressBar(Nucleo.checked, "Bürger", true),
progressLine(true, context),
progressBar(
Nucleo.selected_two, "Artikel und Menge", true),
progressLine(false, context),
progressBar(Nucleo.three, "Buchung", false),
],
),
Container(
margin: EdgeInsets.only(top: 35),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Bürger".toUpperCase(),
style: TextStyle(
fontSize: 13,
color: Colors.grey,
fontWeight: FontWeight.bold),
),
new Padding(
padding: EdgeInsets.only(top: 3),
),
Text(
getCitizenInformation(),
style: TextStyle(
fontSize: 17, color: secondaryColor),
)
],
),
),
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(top: 30),
// width: 600,
child: Row(children: [
Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Artikel und Menge wählen",
style: TextStyle(
color: secondaryColor,
fontSize: 21,
fontWeight: FontWeight.bold),
),
Container(
margin: EdgeInsets.only(top: 4),
height: 5,
width: 30,
color: secondaryColor)
],
),
]),
)
],
),
Row(
children: [
Container(
margin: EdgeInsets.only(top: 40),
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.transparent),
width: 600,
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Wrap(
alignment: WrapAlignment.spaceBetween,
children: <Widget>[
for (var article in articlesList.keys)
articleCard(
article,
MdiIcons.chessQueen,
articlesList[article])
],
),
Row(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 40),
height: 70,
width: 600,
decoration: new BoxDecoration(
borderRadius:
BorderRadius.circular(10),
color: Colors.white),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 220,
margin:
EdgeInsets.only(left: 10),
child: TextField(
onChanged: (text) {
totalPrice = calculatePrice(
text, price);
},
keyboardType:
TextInputType.number,
controller: amountController,
decoration: InputDecoration(
labelStyle: TextStyle(
fontSize: 13),
labelText:
"$articleSelected"),
),
),
Text(
"á € $price / $unit",
style: TextStyle(
color: primaryColor,
fontSize: 20),
),
Text(
"$totalPrice€",
style: TextStyle(
color: secondaryColor,
fontSize: 20,
fontWeight:
FontWeight.bold),
),
],
),
),
],
),
Container(
margin: EdgeInsets.only(top: 30),
child: Row(
crossAxisAlignment:
CrossAxisAlignment.end,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
ButtonTheme(
minWidth: 280,
height: 50,
child: OutlineButton(
borderSide: BorderSide(
color: mainColor, width: 2),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
10)),
child: Text(
"Zurück",
style: TextStyle(
color: mainColor,
fontSize: 16,
),
),
onPressed: () {
Navigator.pop(context);
},
),
),
MaterialButton(
minWidth: 280,
height: 50,
color: buttonColor,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
10)),
child: Text(
"Weiter",
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
onPressed: () {
if (isArticleSelected == true &&
isPriceSelected == true &&
inputAmount != 0) {
Navigator.push(
context,
PageTransition(
type: PageTransitionType
.rightToLeftWithFade,
child:
Controlscreen()));
} else {
Fluttertoast.showToast(
msg:
"Eingaben bitte überprüfen",
toastLength:
Toast.LENGTH_SHORT,
gravity:
ToastGravity.BOTTOM,
timeInSecForIos: 1,
backgroundColor:
Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
}),
],
),
)
]),
),
],
),
]))))
]));
}
String calculatePrice(String inputText, double price) {
double amount;
if (inputText.isNotEmpty) {
amount = double.parse(inputText);
} else {
amount = 0;
}
double total = (amount * price);
setState(() {
totalPrice = total.toStringAsFixed(2);
isPriceSelected = true;
inputAmount = amount;
buttonColor = mainColor;
});
displayedTotalPrice = totalPrice;
displayedWeight = amount.toString();
displayedPrice = price.toString();
return totalPrice;
}
}
You can use a variable to know if a button is already pressed. Like this:
var isSelected = false;
FlatButton(
onPressed: () => { isSelected = true },
child: Text(
"Selling"
),
color: isSelected ? Theme.of(context).primaryColor : Colors.grey,
),
I would like to customize my TabBar.
Right now I have this TabBar (stock UI) :
and I would like to have this UI :
I already coded the personalized tab but I don't know how to implement it.
There is my current code about my HomePage :
class HomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController =
TabController(length: 6, vsync: this); // initialise it here
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: _tabController,
isScrollable: true,
tabs: [
Tab(text: "NewPay1.1"),
Tab(text: "NewMall 1.0"),
Tab(text: "海报"),
Tab(text: "企业版"),
Tab(text: "个版"),
Tab(text: "poa"),
],
),
title: Text('tabBar'),
),
body: TabBarView(
controller: _tabController,
children: [
// these are your pages
TaskListPage(),
TestPage(),
],
),
bottomNavigationBar: BottomAppBar(
color: Colors.white,
shape: CircularNotchedRectangle(),
child: Row(
children: <Widget>[
IconButton(
onPressed: () => _tabController.animateTo(0),
icon: Icon(Icons.home),
),
SizedBox(),
IconButton(
onPressed: () => _tabController.animateTo(1),
icon: Icon(Icons.more))
],
mainAxisAlignment: MainAxisAlignment.spaceAround,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
return TestPage().createState();
},
child: Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
),
);
}
}
then my CustomTab class :
class CustomTab extends StatefulWidget {
final Function(int) tabSelected;
final List<String> items;
const CustomTab({Key key, this.tabSelected, this.items}) : super(key: key);
#override
_CustomTabState createState() => _CustomTabState();
}
class _CustomTabState extends State<CustomTab> {
var categorySelected = 0;
#override
Widget build(BuildContext context) {
return _getListCategory();
}
Widget _getListCategory(){
ListView listCategory = new ListView.builder(
itemCount: widget.items.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index){
return _buildCategoryItem(index);
}
);
return new Container(
height: 50.0,
child: listCategory,
color: Colors.grey[200].withAlpha(200),
);
}
Widget _buildCategoryItem(index){
return new InkWell(
onTap: (){
setSelectedItem(index);
print("click");
},
child: new Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: new EdgeInsets.only(left: 10.0),
child: new Material(
elevation: 2.0,
color: categorySelected == index ? Colors.black : Colors.grey,
borderRadius: const BorderRadius.all(const Radius.circular(25.0)),
child: new Container(
padding: new EdgeInsets.only(left: 12.0,top: 7.0,bottom: 7.0,right: 12.0),
child: new Text(widget.items[index],
style: new TextStyle(
color: categorySelected == index ? Colors.white : Colors.black),
),
),
),
)
],
),
);
}
void setSelectedItem(index) {
if(index != categorySelected) {
widget.tabSelected(index);
setState(() {
categorySelected = index;
});
}
}
}
There is already a plugin for this styled tabbar.
https://pub.dartlang.org/packages/bubble_tab_indicator
I hope this is what you are looking for :)
Yours Glup3
Try this code it is very simple
first initialize this
var radius = Radius.circular(150);
Then
class _Class_Name extends State<ClassName> {
var radius = Radius.circular(150);
#override
Widget build(BuildContext context) {
length: 2,
child: Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.white,
centerTitle: true,
leading: // if you need
),
title:
// if you need
// Scrollable rounded Tab bar
body: TabBar(
isScrollable: true,
labelColor: Colors.black,
tabs: <Widget>[
Tab(
text: "Tab 1",
),
Tab(
text: "Tab 2",
),
],
indicator: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(radius)),
color: HexColor('#005866')),
),
Container(
height: 80,
child: TabBarView(
children: <Widget>[
Container(
child: Center(
child: Text("Hello"),
),
),
Container(
child: Center(
child: Text("Hi"),
),
),
),
],
),
),
);
}
I can't distinguish new Firebase Cloud Messaging notifications from older ones in my Flutter UI. How can I fix this? Thanks.
EXAMPLE: 3 users comment on an author's post that already has 2 "seen" comments. The author's post gets a +3 red marble on it. When the author clicks on this post in the Notifications tab, the user is routed to its comments, that +3 reduces to 0, and the bottom tab marble reduces to 3 (6-3=3) as well.
Dummy UI Code and Pics below.
1. A blank "home page;"
2. a dummy notifications page with posts that have been replied to
3. On clicking a post, a comments page.
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
routes: <String, WidgetBuilder>{
"/comment": (BuildContext context) => new commentFoundation(),
},
home: MainScreen());
}
}
//The content of the notification tab.
class Notification extends StatefulWidget {
#override
_NotificationState createState() => new _NotificationState();
}
class _NotificationState extends State<Notification> {
#override
Widget build(BuildContext context) {
return _buildPostList();
}
Widget _buildPostList() {
return new Scaffold(
backgroundColor: Colors.blue,
body: new Scrollbar(
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new Container(
child: new Stack(children: <Widget>[
new Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 0.0, left: 12.0),
child: DummyPost()),
],
),
replyNotification(),
]));
},
itemCount: 2,
)));
}
Widget replyNotification() {
return new Positioned(
left: 175,
top: 205.5,
child: new Container(
padding: EdgeInsets.only(left: 3.0, right: 3.0),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(30),
),
constraints: BoxConstraints(
minWidth: 30,
minHeight: 30,
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 0.0),
child: new Text(
'+',
style: new TextStyle(
color: Colors.white,
fontSize: 26,
),
textAlign: TextAlign.center,
)),
Container(
padding: EdgeInsets.only(right: 0.0),
child: new Text(
'3',
style: new TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
)),
],
)),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Center(
child: new Container(
child: Text("HomePageStuff"),
));
}
}
//A dummy post in notififications tab
class DummyPost extends StatefulWidget {
#override
_DummyPostState createState() => new _DummyPostState();
}
class _DummyPostState extends State<DummyPost> {
bool monVal = false;
bool reportPressed = false;
Widget commentButton() {
return RaisedButton(
child: Text("ReplyButton"),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (context) => commentFoundation())),
);
}
#override
Widget build(BuildContext context) {
return postList();
}
Widget postList() {
return Column(children: <Widget>[
new GestureDetector(
//this type works
onTap: () => Navigator.pushNamed(context, '/comment'),
child: new Stack(children: <Widget>[
Column(children: <Widget>[
SizedBox(
height: 10.0,
),
Container(
margin: EdgeInsets.only(top: 35.0),
width: 390.0,
child: Card(
shape: RoundedRectangleBorder(
//15?
borderRadius: BorderRadius.circular(5.0),
),
color: Colors.white,
elevation: 2.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Flexible(
child: ListTile(
// The main post content
subtitle: Container(
height: 130.0,
margin: EdgeInsets.only(
top: 15.0, left: 15.0, right: 15.0),
child: Container(
child: Center(
child: Text(
"This is a dummy post",
textAlign: TextAlign.center,
style: TextStyle(
wordSpacing: 3.0,
color: Colors.black,
fontSize: 18.0),
))),
),
)),
//button row
new Container(
width: 400.0,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
margin: EdgeInsets.only(right: 0.0),
width: 190.0,
height: 40.0,
child: commentButton(),
),
// Text to indicate comment numbers
],
)),
],
))),
]),
]))
]);
}
}
//the entire comment page.
class commentFoundation extends StatefulWidget {
#override
_commentFoundationState createState() => new _commentFoundationState();
}
class _commentFoundationState extends State<commentFoundation> {
ScrollController _scrollController = new ScrollController();
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.green,
appBar: _buildAppBar(),
body: new Stack(children: <Widget>[
ListView.builder(
shrinkWrap: true,
controller: _scrollController,
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
return new individualComment();
}),
]));
}
Widget _buildAppBar() {
return AppBar(
title: Text("REPLIES"),
automaticallyImplyLeading: true,
backgroundColor: Colors.white,
elevation: 0.0,
);
}
}
//Each individual comment you see when you click on a post
class individualComment extends StatefulWidget {
final String title;
const individualComment({Key key, this.title}) : super(key: key);
#override
_individualCommentState createState() => new _individualCommentState();
}
class _individualCommentState extends State<individualComment> {
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
Column(children: <Widget>[
//this used to be an expanded
new Container(
child: Card(
elevation: 0.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new ListTile(
// The avatar
leading: Container(
child: Icon(
Icons.accessibility_new,
)),
// Title, location, and time
// The main post content
subtitle: Container(
margin: EdgeInsets.only(top: 10.0, bottom: 0.0),
child: Text(
"This is a reply",
style: TextStyle(
color: Colors.black,
fontSize: .0364609 *
MediaQuery.of(context).size.width),
),
),
),
],
))),
])
],
);
}
}
//*****This is just the tabbar.
class MainScreen extends StatefulWidget {
#override
_MainScreenstate createState() => new _MainScreenstate();
}
class _MainScreenstate extends State<MainScreen> with TickerProviderStateMixin {
String _lastSelected = '0';
final List<Widget> _bodyOptions = [
HomePage(),
Notification(),
];
int _selectedIndex = 0;
bool tab = true;
_selectedTab(int index) {
setState(() {
_lastSelected = '$index';
});
}
Widget __buildTabs() {
return Scaffold(
body: _bodyOptions.elementAt(int.parse(_lastSelected)),
//around the FAB
backgroundColor: const Color(0xFFF4F4F4),
bottomNavigationBar: new Stack(
children: <Widget>[
FABBottomAppBar(
height: 45.0,
centerItemText: '',
color: Colors.black,
selectedColor: Colors.blue,
notchedShape: CircularNotchedRectangle(),
onTabSelected: _selectedTab,
items: [
FABBottomAppBarItem(iconData: Icons.search, text: 'Home'),
FABBottomAppBarItem(
iconData: Icons.notifications, text: 'Notifications'),
],
),
//the red "notification" marble
new Positioned(
right: 20,
top: 0.5,
child: new Container(
padding: EdgeInsets.all(1),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(12),
),
constraints: BoxConstraints(
minWidth: 20,
minHeight: 20,
),
child: new Text(
'6',
style: new TextStyle(
color: Colors.white,
fontSize: 14,
),
textAlign: TextAlign.center,
),
),
)
],
));
}
#override
Widget build(BuildContext context) {
return __buildTabs();
}
}
//Everything below is boiler plate tabbar code.
class FABBottomAppBarItem {
FABBottomAppBarItem({this.iconData, this.text});
IconData iconData;
String text;
}
class FABBottomAppBar extends StatefulWidget {
FABBottomAppBar({
this.items,
this.centerItemText,
this.height: 60.0,
this.iconSize: 24.0,
this.backgroundColor,
this.color,
this.selectedColor,
this.notchedShape,
this.onTabSelected,
}) {
assert(this.items.length == 2 || this.items.length == 4);
}
final List<FABBottomAppBarItem> items;
final String centerItemText;
final double height;
final double iconSize;
final Color backgroundColor;
final Color color;
final Color selectedColor;
final NotchedShape notchedShape;
final ValueChanged<int> onTabSelected;
#override
State<StatefulWidget> createState() => FABBottomAppBarState();
}
class FABBottomAppBarState extends State<FABBottomAppBar> {
int _selectedIndex = 0;
_updateIndex(int index) {
widget.onTabSelected(index);
setState(() {
_selectedIndex = index;
});
return _selectedIndex;
}
#override
Widget build(BuildContext context) {
List<Widget> items = List.generate(widget.items.length, (int index) {
return _buildTabItem(
item: widget.items[index],
index: index,
onPressed: _updateIndex,
);
});
items.insert(items.length >> 1, _buildMiddleTabItem());
return BottomAppBar(
elevation: 0.0,
notchMargin: 2.0,
shape: CircularNotchedRectangle(),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: items,
),
//color of bottom
color: Colors.white,
);
}
Widget _buildMiddleTabItem() {
return Expanded(
child: SizedBox(
height: widget.height,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: widget.iconSize),
Text(
widget.centerItemText ?? '',
style: TextStyle(color: widget.color),
),
],
),
),
);
}
Widget _buildTabItem({
FABBottomAppBarItem item,
int index,
ValueChanged<int> onPressed,
}) {
Color color = _selectedIndex == index ? widget.selectedColor : widget.color;
return Expanded(
child: SizedBox(
height: widget.height,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () => onPressed(index),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(item.iconData, color: color, size: widget.iconSize),
Text(
item.text,
style: TextStyle(color: color),
)
],
),
),
),
),
);
}
}
This seems to be a broad question and I'm unsure if you're asking for suggestions on how you can implement tracking read and unread notifications, or troubleshooting help on your existing code. I suggest checking tips posted on this thread on how you can manage notification counters.