How to make Single Selectable custom button in Flutter - flutter

I am new in Flutter Development, I am practicing on an app of Airline Booking where user have to select a cabin of Airplane through tapping a button. So, I don't know the type of mentioned buttons and background functions, could anyone like to help me?
import 'package:flutter/material.dart';
class MyToogleButtons extends StatefulWidget {
const MyToogleButtons({Key? key}) : super(key: key);
#override
State<MyToogleButtons> createState() => _MyToogleButtonsState();
}
class _MyToogleButtonsState extends State<MyToogleButtons> {
List<bool> isSelected = [true, false, false];
#override
Widget build(BuildContext context) {
return ToggleButtons(
fillColor: Theme.of(context).primaryColor,
borderColor: Theme.of(context).primaryColor,
direction: Axis.horizontal,
isSelected: isSelected,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 6),
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(
color: Theme.of(context).primaryColor,
)),
child: Text(
"Economy",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 32.0,
),
),
),
Text(
"Economy",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
Text(
"Economy",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
],
);
}
}

You can call onPressed method on ToggleButtons and use like
isSelected: isSelected,
onPressed: (index) {
for (int i = 0; i < isSelected.length; i++) {
isSelected[i] = i == index;
}
setState(() {});
},
Full widget
class MyToogleButtons extends StatefulWidget {
const MyToogleButtons({Key? key}) : super(key: key);
#override
State<MyToogleButtons> createState() => _MyToogleButtonsState();
}
class _MyToogleButtonsState extends State<MyToogleButtons> {
List<bool> isSelected = [true, false, false];
#override
Widget build(BuildContext context) {
return ToggleButtons(
fillColor: Theme.of(context).primaryColor,
borderColor: Theme.of(context).primaryColor,
direction: Axis.horizontal,
isSelected: isSelected,
onPressed: (index) {
for (int i = 0; i < isSelected.length; i++) {
isSelected[i] = i == index;
}
setState(() {});
},
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 6),
decoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(
color: Theme.of(context).primaryColor,
)),
child: Text(
"Economy",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 32.0,
),
),
),
Text(
"Economy",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
Text(
"Economy",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 12.0,
),
),
],
);
}
}

Related

Search Bar Shows Result if Search Term is not Contained Inside Names

I'm working on a big company project and a screen needed search bar but it works ok when you type one Letter or two but then if you continue to type in search it shows the whole names in it how do i fix this i want the list to show nothing when search term is wrong
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:reports/core/locale/locale_helper.dart';
import 'package:reports/core/util/constants.dart';
import 'package:reports/core/util/my_icons.dart';
import 'package:reports/core/util/responsive.dart';
import 'package:reports/features/reports/presentation/widgets/report_app_bar.dart';
import '../../../../../core/util/my_colors.dart';
class Marketer extends Equatable {
Marketer({
required this.name,
required this.code,
});
late String name;
final int code;
#override
List<Object?> get props => [code];
}
class Marketerselect extends StatefulWidget {
Marketer? selectedValue;
Marketerselect({
Key? key,
this.selectedValue,
}) : super(key: key);
#override
State<Marketerselect> createState() => _MarketerselectState();
}
class _MarketerselectState extends State<Marketerselect> {
final TextEditingController _controller = TextEditingController();
List<Marketer> marketerInfo = [
Marketer(name: 'امیررضا مرادی', code: 1),
Marketer(name: 'محمد علی سالان', code: 2),
Marketer(name: 'مهدی قلیزاده ', code: 3),
Marketer(name: 'آرش نوری', code: 4),
Marketer(name: 'نعیم لطفعلی', code: 5),
];
List<Marketer> searchList = [];
#override
void initState() {
_controller.addListener(() {
setState(() {
if (_controller.text.isNotEmpty) {
searchList.clear();
for (var marketer in marketerInfo) {
if (marketer.name.contains(_controller.text)) {
searchList.add(marketer);
}
}
} else {
searchList.clear();
}
});
});
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return ResponsiveWidget(
context: context,
mobile: Directionality(
textDirection: getDirection(context),
child: Scaffold(
appBar: ReportAppBar(
title: 'بازایاب',
hasLeadingWidget: true,
controller: _controller,
isDialog: true,
),
body: Card(
elevation: 8.0,
shadowColor: Colors.grey,
margin: const EdgeInsetsDirectional.only(top: 16),
child: ListView.builder(
itemCount: searchList.isEmpty ? marketerInfo.length : searchList.length,
itemBuilder: (context, index) {
return RadioListTile<Marketer?>(
value: searchList.isNotEmpty ? searchList[index] : marketerInfo[index],
groupValue: widget.selectedValue,
tileColor: Colors.white,
onChanged: (value) {
setState(() {
widget.selectedValue = value!;
Navigator.of(context).pop(value);
});
},
title: Text(
searchList.contains(marketerInfo[index]) ? searchList[index].name : searchList[index].name,
style: const TextStyle(
fontSize: 15.0,
color: MyColor.mine,
fontFamily: Constants.fontFamily,
),
),
);
}),
),
)),
web: Directionality(
textDirection: getDirection(context),
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.white,
title: const Text(
'بازاریاب',
style: TextStyle(
fontSize: 15.0,
color: MyColor.mine,
fontFamily: Constants.fontFamily,
),
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(50),
child: TextField(
keyboardType: TextInputType.text,
controller: _controller,
decoration: InputDecoration(
suffixIcon: Padding(
padding: const EdgeInsetsDirectional.only(end: 16.0),
child: Image.asset(MyIcons.search, color: Colors.black, alignment: AlignmentDirectional.centerEnd)),
hintText: 'جستوجو در لیست بازاریاب ها',
hintStyle: const TextStyle(
fontFamily: Constants.fontFamily,
fontWeight: FontWeight.w400,
fontSize: 12.0,
),
filled: true,
fillColor: Colors.white,
),
style: const TextStyle(
fontSize: 18.0,
color: MyColor.mine,
fontFamily: Constants.fontFamily,
))),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: searchList.isEmpty ? marketerInfo.length : searchList.length,
itemBuilder: (context, index) {
return RadioListTile<Marketer?>(
value: searchList.isNotEmpty ? searchList[index] : marketerInfo[index],
groupValue: widget.selectedValue,
tileColor: Colors.white,
onChanged: (value) {
setState(() {
widget.selectedValue = value!;
});
},
title: Text(
searchList.isNotEmpty ? searchList[index].name : marketerInfo[index].name,
style: const TextStyle(
fontSize: 15.0,
color: MyColor.mine,
fontFamily: Constants.fontFamily,
),
),
);
}),
),
const Divider(
color: MyColor.mercury,
thickness: 1.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsetsDirectional.only(bottom: 8.0, end: 8.0),
child: MaterialButton(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
onPressed: () {
Navigator.of(context).pop(widget.selectedValue);
},
color: MyColor.main,
child: const Text(
'تأیید',
style: TextStyle(
fontSize: 14.0,
color: Colors.white,
fontFamily: Constants.fontFamily,
),
),
),
)
],
),
],
),
))).get();
}
}
This is the whole page with data and search bar in it
It would be appreciated if anyone could help me

Flutter TabController late initializer

I am creating an app and I am working on the profile setup and am using a tabcontroller. I have my tabcontroller working to navigate my first 3 screens, but for some reason I get a "late initializtion" error for my last screen. I have a custom button that I use for each screen, and the error gets shown once I add the custom button to my last acrren. Could someone explain to me what I need to do to get it working for my last screen? I've attached my code for the tabcontroller, custom button, and my last screen:
Tabcontroller onboarding model:
class AccountOnboarding extends StatefulWidget {
const AccountOnboarding({Key? key}) : super(key: key);
#override
State<AccountOnboarding> createState() => _AccountOnboardingState();
}
class _AccountOnboardingState extends State<AccountOnboarding> {
static const List<Tab> tabs = <Tab>[
Tab(text: 'Name'),
Tab(text: 'Age and Profile'),
Tab(text: 'Bio and Interests'),
Tab(text: 'Selection')
];
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: tabs.length,
child: Builder(builder: (BuildContext context) {
final TabController tabController = DefaultTabController.of(context)!;
tabController.addListener(() {
if (!tabController.indexIsChanging) {}
});
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
title: Row(
children: [
Expanded(
child: Image.asset('assets/images/Logo_Strength.png',
height: 50),
),
Expanded(
flex: 2,
child: RichText(
text: TextSpan(
style: GoogleFonts.montserrat(
fontSize: 30),
children: <TextSpan> [
TextSpan(text: 'Stren',
style: GoogleFonts.montserrat(
color: Colors.white,
fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
])),
TextSpan(text: ';',
style: GoogleFonts.montserrat(
color: const Color(0xffef6a7a), fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
])),
TextSpan(text: 'th',
style: GoogleFonts.montserrat(
color: Colors.white,
fontWeight: FontWeight.bold,
letterSpacing: 1,
shadows: [
Shadow(
color: Colors.black.withOpacity(0.7),
offset: const Offset(1.5, 0.0))
]))
],
),
),
),
],
)
),
body: TabBarView(
// physics: const NeverScrollableScrollPhysics(),
children: [
NamePage(tabController: tabController,),
ageAndPicture(tabController: tabController,),
bioAndInterests(tabController: tabController,),
SelectionPage(tabController: tabController,)
],
),
);
}));
}}
Custom Button:
class CustomButton extends StatelessWidget {
final TabController tabController;
const CustomButton({Key? key,
required this.tabController})
: super(key: key);
#override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
vertical: 16),
elevation: 0,
primary: Colors.transparent
),
onPressed: () {
tabController.animateTo(tabController.index + 1);
},
child: Container(
width: double.infinity,
child: Center(
child: Text('Continue',
style: GoogleFonts.montserrat(
color: const Color.fromARGB(255, 20, 83, 106),
fontSize: 19,
fontWeight: FontWeight.w600
),),
),
)
),
);
}
}
Last Screen code:
class SelectionPage extends StatefulWidget {
final TabController tabController;
const SelectionPage({Key? key,
required this.tabController}) : super(key: key);
#override
_SelectionPageState createState() => _SelectionPageState();
}
class _SelectionPageState extends State<SelectionPage>{
List <Item>listOfModel = [];
late TabController tabController;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
String retrieveString;
final data = ModalRoute.of(context)!.settings;
if (data.arguments == null) {
retrieveString = "empty";
} else {
retrieveString = data.arguments as String;
}
listOfModel.add(Item(title: "Maintaining healthy relationships"));
listOfModel.add(Item(title: "Stress and anxiety management"));
listOfModel.add(Item(title: "Maintaing a better work-life balance"));
listOfModel.add(Item(title: "Personal growth and development"));
listOfModel.add(Item(title: "Being happier and more content in life"));
listOfModel.add(Item(title: "Mental and emotional well-being"));
double _height = MediaQuery.of(context).size.height;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
body: Padding(
padding: EdgeInsets.only(
left: 30,
right: 30,
top: _height * 0.07,
bottom: _height * 0.05),
child: Column(
children: [
Column(
children: [
Column(
children: <Widget>[
Text('Hello there $retrieveString! What all would you like to focus on?',
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 19,
fontWeight: FontWeight.w600
),
textAlign: TextAlign.center,),
const SizedBox(height: 10),
Text("You can pick all that apply:",
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 14.5,
fontWeight: FontWeight.w600
),),
const SizedBox(height: 15,),
GridView.count(
primary: true,
shrinkWrap: true,
padding: const EdgeInsets.all(10),
childAspectRatio: 1.15,
crossAxisCount: 2,
crossAxisSpacing: 25,
mainAxisSpacing: 25,
children: [
gridItem(listOfModel[0],MyFlutterApp.relationships),
gridItem(listOfModel[1],MyFlutterApp2.meditate),
gridItem(listOfModel[2],MyFlutterApp.balance),
gridItem(listOfModel[3],MyFlutterApp2.personal_growth),
gridItem(listOfModel[4],MyFlutterApp.happy),
gridItem(listOfModel[5],MyFlutterApp3.well_rounded),
],
),
const SizedBox(height: 18,),
],
),
CustomButton(tabController: tabController)
],
),
],
),
),
);
}
Widget gridItem(Item item, IconData icon){
return GestureDetector(
onTap: () {
setState(() {
item.isSelected = !item.isSelected;
});
},
child: Stack(
children: [Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: item.isSelected ? Color.fromARGB(255, 234, 188, 193) : Colors.white
),
child: Column(
children: [
Align(alignment: Alignment.topCenter,
child: Icon(
icon,
color: const Color(0xff31708c),
size: 45,
),
),
const SizedBox(height: 4,),
Text(item.title,
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,),
],
),
),
Positioned(
top: 0,
right: 0,
child: Offstage(
offstage: !item.isSelected,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(width: 2.5),
shape: BoxShape.circle),
child: const Icon(
Icons.check,
color: Colors.green,
),
),
),
)
],
)
);
}
}
class Item{
String title;
bool isSelected;
Item({required this.title, this.isSelected = false});
}
Remove
late TabController tabController;
in SelectionPage and change
CustomButton(tabController: tabController)
in SelectionPage to
CustomButton(tabController: widget.tabController)

The named parameter 'key' is required, but there's no corresponding argument.-in flutter app developing

I'm getting this error called The named parameter 'key' is required, but there's no corresponding argument. I'm developing a simple BMI calculator app using flutter, android studio. didn't understand about the error I'm new to flutter. can anyone tell me what to do about this error? followed up this youtube video and the code is here github.
import 'package:bmi_cal/constants/app_constants.dart';
import 'package:bmi_cal/widgets/left_bar.dart';
import 'package:bmi_cal/widgets/right_bar.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
TextEditingController _heightController = TextEditingController();
TextEditingController _weightController = TextEditingController();
double _bmiResult = 0;
String _textResult = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"BMI Calculator",
style:
TextStyle(color: accentHexColor, fontWeight: FontWeight.w300),
),
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
),
backgroundColor: mainHexColor,
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 130,
child: TextField(
controller: _heightController,
style: TextStyle(
fontSize: 42,
fontWeight: FontWeight.w300,
color: accentHexColor),
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Height",
hintStyle: TextStyle(
fontSize: 42,
fontWeight: FontWeight.w300,
color: Colors.white.withOpacity(.8)),
),
),
),
Container(
width: 130,
child: TextField(
controller: _weightController,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 42,
fontWeight: FontWeight.w300,
color: accentHexColor),
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Weight",
hintStyle: TextStyle(
fontSize: 42,
fontWeight: FontWeight.w300,
color: Colors.white.withOpacity(.8)),
),
),
),
],
),
SizedBox(
height: 30,
),
GestureDetector(
onTap: () {
double _h = double.parse(_heightController.text);
double _w = double.parse(_weightController.text);
setState(() {
_bmiResult = _w / (_h * _h);
if(_bmiResult > 25){
_textResult = "You\'re over weight";
} else if(_bmiResult >= 18.5 && _bmiResult <= 25){
_textResult = "You have normal weight";
}else{
_textResult = "You\'re under weight";
}
});
},
child: Container(
child: Text(
"Calculate",
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: accentHexColor),
),
),
),
SizedBox(
height: 50,
),
Container(
child: Text(
_bmiResult.toStringAsFixed(2),
style: TextStyle(fontSize: 90, color: accentHexColor),
),
),
SizedBox(
height: 30,
),
Visibility(
visible: _textResult.isNotEmpty,
child: Container(
child: Text(
_textResult,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w400,
color: accentHexColor),
),
)),
SizedBox(height: 10,),
LeftBar(barWidth: 40,),
SizedBox(height: 20,),
LeftBar(barWidth: 70),
SizedBox(height: 20,),
LeftBar(barWidth: 40,),
SizedBox(height: 20,),
RightBar(barWidth: 70),
SizedBox(height: 50,),
RightBar(barWidth: 70),
],
),
));
}
}
main.dart
import 'package:bmi_cal/screens/home.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'BMI calculator',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.yellow,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeScreen(),
);
}
}
This error normally indicates, that the widget you are trying to add to the widget tree does have a constructor similar to the following:
const LeftBar({required Key key, #required this.barWidth}) : super(key: key);
The error seems to be related to the first required argument with the name key. Just remove the required keyword, since it the key is mostly needed for testing the widget and should be optional.
I checked your source code on github and I dont think it is up to date for this example.
enter image description here
You have to just try this:
Add "VoidCallback" instead of "Function" onpress.
Remove # sign
Add required keyword
for detail see the below picture
enter image description here

Shape of FilterChip in flutter

I want to design this type of layout but I don't know how to give shape to FilterChip
but I'm getting this layout
My code is
class FilterChipWidget extends StatefulWidget {
final String chipName;
const FilterChipWidget({Key? key, required this.chipName}) : super(key: key);
#override
_FilterChipWidgetState createState() => _FilterChipWidgetState();
}
class _FilterChipWidgetState extends State<FilterChipWidget> {
var _isSelected = false;
#override
Widget build(BuildContext context) {
return FilterChip(
showCheckmark: false,
label: Text(widget.chipName),
labelStyle: GoogleFonts.robotoSlab(
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
fontSize: 13,
color: Colors.black),
selected: _isSelected,
backgroundColor: fTextFieldColor,
onSelected: (isSelected) {
setState(() {
_isSelected = isSelected;
});
},
selectedColor: Colors.blueAccent,
);
}
}
interest.dart
Align(
alignment: Alignment.center,
child: Container(
child: Wrap(
spacing: 5.0,
runSpacing: 5.0,
children: [
FilterChipWithImageWidget(chipName: 'Stocks'),
FilterChipWidget(chipName: 'Crypto'),
FilterChipWidget(chipName: 'Market'),
FilterChipWidget(chipName: 'Jobs'),
FilterChipWidget(chipName: 'Investment'),
FilterChipWidget(chipName: 'Entrepreneur'),
FilterChipWidget(chipName: 'Business'),
FilterChipWidget(chipName: 'Venture\nCapital'),
FilterChipWidget(chipName: 'Advertise'),
],
),
),
)
FilterChip accepts a value named shape. You can define it as shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ) or you can use container and customise it
return InkWell(
onTap:(){
setState((){
_isSelected = !_isSelected;
});
},
child:Container(
decoration: BoxDecoration(
color: _isSelected? Colors.blueAccent : fTextFieldColor,
borderRadius:BorderRadius.circular(5),
),
child: Row(
mainAxisSize:MainAxisSize.min,
children:[
Image.asset("image path here", width:15),
Text(widget.chipName, style: GoogleFonts.robotoSlab(
fontStyle: FontStyle.normal,
fontWeight: FontWeight.w400,
fontSize: 13,
color: Colors.black),),
]
)
)
);
use this instead of returning FilterChip.

How to add user-submitted tags data from "material_tag_editor" into a "Flutter Form Builder" form?

I am building a form using the "Flutter Form Builder" package 4.0.2 and trying to add two fields where users enter "tags" via the "material_tag_editor" package 0.0.6
The Problem: when then form is submitted by pressing the "Post" button, neither of the data submitted for those "tag" form fields (Q1 or Q3) is included (see screenshot of the console below).
Notice the line "flutter: {qFour: 30, qFive: sample answer to q5, qTen: sample answer to q10}" - neither Q1 nor Q3 are included (I added their data in separate print statements, so you see them in the console - look for the >>> lines).
Here are screenshots of the form with sample tags entered (iPhone simulator screenshot), and the bottom of the form with the button:
Here's the code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:streakers_journal_beta/screens/reviews_screen.dart';
import 'package:streakers_journal_beta/screens/welcome_screen.dart';
import 'package:streakers_journal_beta/models/user.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
// BEGIN code from material_tag_editor
import 'package:material_tag_editor/tag_editor.dart';
import 'package:material_tag_editor/tag_editor_layout_delegate.dart';
import 'package:material_tag_editor/tag_layout.dart';
import 'package:material_tag_editor/tag_render_layout_box.dart';
// END code from material_tag_editor
//import 'dart:html';
//import 'dart:convert';
// This is the stateful widget that the main application instantiates, per https://api.flutter.dev/flutter/widgets/Form-class.html
class SandboxWriteReviewScreen extends StatefulWidget {
// BEGIN code from material_tag_editor
final String title = 'Material Tag Editor Demo';
// END code from material_tag_editor
#override
_SandboxWriteReviewScreenState createState() =>
_SandboxWriteReviewScreenState();
}
// This is the private State class that goes with WriteReviewScreen
class _SandboxWriteReviewScreenState extends State<SandboxWriteReviewScreen> {
var data;
AutovalidateMode autovalidateMode = AutovalidateMode.always;
bool readOnly = false;
bool showSegmentedControl = true;
//final _newFormbuilderKey = GlobalKey<FormState>();
final _newnewFormbuilderKey = GlobalKey<FormBuilderState>();
// above "GlobalKey" lets us generate a unique, app-wide ID that we can associate with our form, per https://fluttercrashcourse.com/blog/realistic-forms-part1
final ValueChanged _onChanged = (val) => print(val);
// BEGIN related to FormBuilderTextField in form below
final _ageController = TextEditingController(text: '45');
bool _ageHasError = false;
// END related to FormBuilderTextField in form below
String qEleven;
String qTwelve;
// BEGIN code from material_tag_editor
List<String> qOne = [];
final FocusNode _focusNode = FocusNode();
onDelete(index) {
setState(() {
qOne.removeAt(index);
});
}
// below = reiteration for cons
List<String> qThree = [];
//final FocusNode _focusNode = FocusNode();
uponDelete(index) {
// NOTE: "uponDelete" for cons vs. "onDelete" for pros
setState(() {
qThree.removeAt(index);
});
}
// END code from material_tag_editor
//final _user = User();
List<bool> isSelected;
int starIconColor =
0xffFFB900; // was 0xffFFB900; 0xffD49428 is from this image: https://images.liveauctioneers.com/houses/logos/lg/bartonsauction550_large.jpg?auto=webp&format=pjpg&width=140
#override
void initState() {
//isSelected = [true, false];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Padding(
padding: EdgeInsets.only(right: 12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.keyboard_backspace),
onPressed: () {
Navigator.pop(context);
},
),
Text(
'back',
style: TextStyle(
fontSize: 7,
),
),
],
),
),
],
leading: Icon(
Icons.rate_review,
color: Colors.black54,
),
title: Column(
children: [
Text(
'SANDBOX Write a Review',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
SizedBox(
height: 6.0,
),
Text(
'flutter_form_builder ^4.0.2',
style: TextStyle(
color: Colors.limeAccent,
fontSize: 14,
),
),
SizedBox(
height: 6.0,
),
],
),
// BEGIN appBar gradient code, per https://medium.com/flutter-community/how-to-improve-your-flutter-application-with-gradient-designs-63180ba96124
flexibleSpace: Container(
decoration: BoxDecoration(
color: Colors.indigoAccent,
),
),
backgroundColor: Colors.white,
centerTitle: false,
),
body: SingleChildScrollView(
child: Container(
child: Builder(
builder: (context) => FormBuilder(
// was "builder: (context) => Form("
key: _newnewFormbuilderKey,
initialValue: {
'date': DateTime.now(),
},
child: Padding(
padding: const EdgeInsets.all(14.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 12.0,
),
RichText(
text: TextSpan(
style: TextStyle(
color: Colors.blue,
),
children: <TextSpan>[
TextSpan(
text:
'Q1 via TagEditor', // was 'What are 3 good or positive things about the house, property or neighborhood?', // [ 1 ​]
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
TextSpan(
text: ' (optional)',
style: TextStyle(
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 14.0,
color: Colors.black54,
), // was 'misleading or inaccurate?',
),
],
),
),
// BEGIN code from material_tag_editor
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: TagEditor(
length: qOne.length,
delimiters: [
','
], // was delimiters: [',', ' '], Also tried "return" ('\u2386',) and '\u{2386}'
hasAddButton: true,
textInputAction: TextInputAction
.next, // moves user from one field to the next!!!!
autofocus: false,
maxLines: 1,
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Colors.lightBlue),
// borderRadius: BorderRadius.circular(20.0),
// ),
inputDecoration: const InputDecoration(
// below was "border: InputBorder.none,"
isDense: true,
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlue),
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
// above is per https://github.com/flutter/flutter/issues/5191
),
labelText: 'separate, with, commas',
labelStyle: TextStyle(
fontStyle: FontStyle.italic,
backgroundColor:
Color(0x65dffd02), // was Color(0xffDDFDFC),
color: Colors.black87, // was Color(0xffD82E6D),
fontSize: 14,
),
),
onTagChanged: (value) {
setState(() {
qOne.add(value);
});
},
tagBuilder: (context, index) => _Chip(
index: index,
label: qOne[index],
onDeleted: onDelete,
),
),
),
// END code from material_tag_editor
SuperDivider(),
// END Chips Input
RichText(
text: TextSpan(
style: TextStyle(
color: Colors.blue,
),
children: <TextSpan>[
TextSpan(
text:
'​​Q3 via TagEditor (skipped Q2, for simplicity)', // [ 2 ​] was '​​List up to 3 negatives, or things you don’t like, about the house, property or neighborhood:',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
TextSpan(
text: '(optional)', // was text: '\n(optional)',
style: TextStyle(
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 14.0,
backgroundColor:
Color(0x70DDFDFC), // was Color(0x30F8A0A2),
color: Colors.black54, // was Color(0xffD82E6D),
//color: Colors.black54,
), // was 'misleading or inaccurate?',
),
],
),
),
// BEGIN code from material_tag_editor
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: TagEditor(
length: qThree.length,
delimiters: [','], // was delimiters: [',', ' '],
hasAddButton: true,
textInputAction: TextInputAction
.next, // moves user from one field to the next!!!!
autofocus: false,
maxLines: 1,
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Colors.lightBlue),
// borderRadius: BorderRadius.circular(20.0),
// ),
inputDecoration: const InputDecoration(
// below was "border: InputBorder.none,"
isDense: true,
border: OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlue),
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
// above is per https://github.com/flutter/flutter/issues/5191
),
labelText: 'separate, with, commas',
labelStyle: TextStyle(
fontStyle: FontStyle.italic,
backgroundColor:
Color(0x65dffd02), // was Color(0xffDDFDFC),
color: Colors.black87, // was Color(0xffD82E6D),
fontSize: 14,
),
),
onTagChanged: (value) {
setState(() {
qThree.add(value);
});
},
tagBuilder: (context, index) => _Chip(
index: index,
label: qThree[index],
onDeleted: uponDelete,
),
),
),
// END code from material_tag_editor
SuperDivider(),
RichText(
text: TextSpan(
style: TextStyle(
color: Colors.blue,
),
children: <TextSpan>[
TextSpan(
text:
'​​Q4 - via FormBuilder\'s FormBuilderRadioGroup', // [ 3 ​]
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
TextSpan(
text: ' (required)',
style: TextStyle(
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 14.0,
color: Colors.red[700],
), // was 'misleading or inaccurate?',
),
],
),
),
FormBuilderRadioGroup(
name: 'qFour',
decoration: const InputDecoration(
border: InputBorder.none,
labelStyle: TextStyle(fontStyle: FontStyle.italic),
),
wrapVerticalDirection: VerticalDirection.down,
// orientation: GroupedRadioOrientation.vertical,
orientation: OptionsOrientation.vertical,
onChanged: _onChanged,
options: [
FormBuilderFieldOption(
value: '0', child: Text('Never')),
FormBuilderFieldOption(
value: '30', child: Text('Within the last month')),
FormBuilderFieldOption(
value: '180',
child: Text('Within the last 6 months')),
FormBuilderFieldOption(
value: '181',
child: Text('More than 6 months ago')),
],
),
SuperDivider(),
Center(
child: RichText(
text: TextSpan(
style: TextStyle(
color: Colors.blue,
),
children: <TextSpan>[
TextSpan(
text:
'Q5 - via FormBuilder\'s FormBuilderTextField', // [ 4 ​]
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
TextSpan(
text: ' (optional)',
style: TextStyle(
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 14.0,
color: Colors.black54,
), // was 'misleading or inaccurate?',
),
],
),
),
),
GavTextField(
maxCharLength: 200,
fieldAttribute: 'qFive',
fieldLabelText: '',
),
SuperDivider(),
RichText(
text: TextSpan(
style: TextStyle(
color: Colors.blue,
),
children: <TextSpan>[
TextSpan(
text:
'Q10 - via FormBuilder\'s FormBuilderTextField (skipped Q6 - Q9, for simplicity)', // [ 9 ​]
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
TextSpan(
text: ' (optional)',
style: TextStyle(
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 14.0,
color: Colors.black54,
), // was 'misleading or inaccurate?',
),
],
),
),
GavTextField(
maxCharLength: 1200,
fieldAttribute: 'qTen',
fieldLabelText:
'Be honest & kind.', // was 'Be honest, but kind.',
),
SuperDivider(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.purple,
padding: EdgeInsets.symmetric(
horizontal: 50, vertical: 20),
textStyle: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)),
onPressed: () {
_newnewFormbuilderKey.currentState.save();
if (_newnewFormbuilderKey.currentState
.validate()) {
print(_newnewFormbuilderKey.currentState.value);
print(
' >>> Q1\'s value via separate print: {$qOne}',
);
print(
' >>> Q3\'s value via separate print: {$qThree}',
);
} else {
print("validation failed");
}
},
child: Text(
'Post',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
],
),
),
SizedBox(
height: 200.0,
),
],
),
),
),
),
),
),
);
}
}
class GavTextField extends StatelessWidget {
GavTextField(
{#required this.maxCharLength,
#required this.fieldAttribute,
#required this.fieldLabelText});
int maxCharLength;
String fieldAttribute;
String fieldLabelText;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FormBuilderTextField(
name: '$fieldAttribute',
// BEGIN countdown to max number of characters, per https://stackoverflow.com/a/64035861/1459653
maxLength: maxCharLength,
maxLines: null,
buildCounter: (
BuildContext context, {
int currentLength,
int maxLength,
bool isFocused,
}) {
return Text(
'${maxLength - currentLength}',
);
},
// END countdown to max number of characters, per https://stackoverflow.com/a/64035861/1459653
decoration: InputDecoration(
labelText:
'$fieldLabelText', // was " Separate items, with, commas",
//counterText: _textController.text.length.toString(),
labelStyle: TextStyle(
fontSize: 12.5,
fontStyle: FontStyle.italic,
),
//helperText: 'Separate, with, commas',
//floatingLabelBehavior: ,
// filled: true,
// fillColor: Colors.lightBlue.withOpacity(0.05),
// BEGIN change border if focus
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlue),
borderRadius: BorderRadius.circular(20.0),
),
// END change border if focus
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: BorderSide(),
),
),
textInputAction:
TextInputAction.next, // moves user from one field to the next!!!!
autofocus:
false, // on screen load, first text field is already active - user can just start typing
),
);
}
} //</formstate>`
var alertStyle = AlertStyle(
animationType: AnimationType.fromTop,
isCloseButton: true,
isOverlayTapDismiss: true,
descTextAlign: TextAlign.start,
alertBorder: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
side: BorderSide(
color: Colors.grey,
),
),
titleStyle: TextStyle(
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
fontSize: 16,
color: Colors.black54,
),
alertAlignment: Alignment.topCenter,
);
// BEGIN code from material_tag_editor
class _Chip extends StatelessWidget {
const _Chip({
#required this.label,
#required this.onDeleted,
#required this.index,
});
final String label;
final ValueChanged<int> onDeleted;
final int index;
#override
Widget build(BuildContext context) {
return Chip(
backgroundColor: Colors.blueGrey.shade100,
labelPadding: const EdgeInsets.only(left: 8.0),
label: Text(label),
deleteIcon: Icon(
Icons.cancel_rounded, // was "Icons.close,"
size: 18,
),
onDeleted: () {
onDeleted(index);
},
);
}
}
// END code from material_tag_editor
class SuperDivider extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
top: 4.0,
bottom: 4.0,
),
child: const Divider(
color: Colors.white70,
height: 30,
thickness: 0.1,
indent: 0,
endIndent: 0,
),
);
}
}
Flutter form builder assumes that only form children's will be used which automatically updates ancestor form whenever their value is changed. But since tag builder is not a form widget, you can do two things -
Wrap these widgets inside a new form widget, whose responsibility will be to only send updates to the ancestor form and render its child.
You can do something like
class GenericFormWidget<T> extends StatefulWidget {
GenericFormWidget({
Key key,
#required this.attribute,
#required this.builder,
}) : super(key: key);
final String attribute;
final Function(BuildContext, Function(T value)) builder;
#override
Widget build(BuildContext context) {
return widget.builder(context, _updateValue);
}
void _updateValue(T value) =>
_formState.setAttributeValue(widget.attribute, value);
}
Instead of using flutter form builder, you can have use Flutter form and create your own field UI using material widgets. This will be costly for you since you will need to migrate existing fields too.