Related
Try create Dynamic Widget, data from API and add widget in array
&showing in listbuilder but when I click on dropdown, radion selection
not redering. When I click on radio button value print in terminal but
changes not visible same for dropdown and filter chip also.
I want to create form dynamically based on API value like type=TextAREA so create textfield, Type=radioButton so create radio button
class ObservationCreate extends StatefulWidget {
static String tag = '/ObservationCreate';
#override
ObservationCreateState createState() => ObservationCreateState();
}
class ObservationCreateState extends State<ObservationCreate> {
PageController pageController = PageController(initialPage: 0);
int pageNumber = 0;
String token;
String positionSelection;
Animation buttonSqueezeanimation;
AnimationController buttonController;
var radioValue, previouseValue;
var getDatas;
List<EmployeeModel> employee = [];
List<OrganizationModel> organizations = [];
List<CommonModel> common = [];
List<TextEditingController> controllers = [];
List<dynamic> _selectedValues = [];
List<MultiSelectionModel> _multiSelection = [];
List<Widget> buildDotIndicator() {
List<Widget> list = [];
for (int i = 0; i <= 2; i++) {
list.add(i == pageNumber ? indicator(isActive: true) : indicator(
isActive: false));
}
return list;
}
List<Widget> _Widget = new List();
List<Widget> _ObservationDetailsWidget = new List();
List<int> _display = new List();
var masterItems;
bool getMaster = false, observation = false;
SharedPreferences prefs;
int number = 1;
bool selected = false;
#override
void initState() {
retrive();
}
Future<void> getMasterDatas(String controlType, var code) async {
Response response =
await get(getMasterData, headers: headers).timeout(
Duration(seconds: timeOut));
print("masterData: " + response.body);
getDatas = json.decode(response.body);
String error = getDatas["error"];
if (error != Error) {
setState(() {
getMaster = true;
});
var count = getDatas["items"].length;
print(code+count.toString());
if(common.length != 0){
common.removeWhere((element) => element.id == code);
}
for (int i = 0; i < count; i++) {
if (getDatas['items'][i]['masterData']['masterDataObjectId'] == code) {
var masterData = getDatas['items'][i]['masterData'];
var masterDataObject = getDatas['items'][i]['masterDataObject'];
print(i);
CommonModel commonModel = new CommonModel(masterData['value'], masterData['masterDataObjectId'],
masterDataObject['masterDataObjectValue'], masterData['showControlIDs'] == null ? " " : masterData['showControlIDs']);
common.add(commonModel);
}
}
if(getMaster){
print(getMaster);
switch (controlType){
case "RADIOBUTTON":
_Widget.add(radioitem(code));
break;
case "MASTERDROPDOWN":
_Widget.add(masterDropDownBox(code));
break;
case "MULTISELECT":
_ObservationDetailsWidget.add(multiSelections(code));
_getListings(code);
break;
}
}
} else {
print(error);
}
}
Future<void> getObsProperty() async {
var items;
String url = "https://webgateway.demoehswatch.com/api/observations-service/propertysettings/GetListPropertyAsync" +
"?Authorization=bearer" + token + "&MaxResultCount=1000";
final Uri getObsPropertyData = Uri.parse(url);
Response response =
await get(getObsPropertyData, headers: header).timeout(
Duration(seconds: timeOut));
var getData = json.decode(response.body);
String error = getData["error"];
if (error != Error) {
var count = getData["items"].length;
for (int i = 0; i < count; i++) {
if (getData['items'][i]['providerName'] == "Observation" &&
getData['items'][i]['visible'] &&
getData['items'][i]['defaultDisplay'] &&
getData['items'][i]['psDisplaySection'] == "Draft") {
items = getData['items'][i];
print(items["controlType"]+" "+items["name"]);
_display.add(items["displayOrderInView"]);
_display.sort();
}
}
for (int i = 0; i < _display.length; i++) {
for (int j = 0; j < count; j++) {
if (getData['items'][j]['providerName'] == "Observation" &&
getData['items'][j]['visible'] &&
getData['items'][j]['defaultDisplay'] &&
getData['items'][j]['psDisplaySection'] == "Draft") {
var ite = getData['items'][j];
if (_display[i].toString() == ite["displayOrderInView"].toString()) {
switch(ite['controlType']){
case "TEXTBOX":
TextEditingController controller = TextEditingController();
controllers.add(controller);
setState(() {
if (ite['masterDataObjectCode'] == "")
_Widget.add(dynamicText(
ite['name'].toString().split("Observation.")[1],
textColor: textColor));
_Widget.add(dynamicTextbox(50, controller));
});
break;
case "RADIOBUTTON":
print(ite['masterDataObjectCode']);
var codeRadio = ite['masterDataObjectCode'];
getMasterDatas(ite['controlType'], codeRadio);
print(getMaster);
break;
case "MASTERDROPDOWN":
print(ite['masterDataObjectCode']);
var codeDropDown = ite['masterDataObjectCode'];
getMasterDatas(ite['controlType'], codeDropDown);
break;
}
}
}
}
}
} else {
print(error);
}
}
Future<void> getObsPropertyObservationDetails(String objectCode) async {
var items;
String url = "https://webgateway.demoehswatch.com/api/observations-service/propertysettings/GetListPropertyAsync" +
"?Authorization=bearer" + token + "&MaxResultCount=1000";
final Uri getObsPropertyData = Uri.parse(url);
Response response =
await get(getObsPropertyData, headers: header).timeout(
Duration(seconds: timeOut));
var getData = json.decode(response.body);
String error = getData["error"];
if (error != Error) {
var count = getData["items"].length;
for (int i = 0; i < count; i++) {
if (getData['items'][i]['providerName'] == "Observation" &&
getData['items'][i]['visible'] &&
getData['items'][i]['psDisplaySection'] == "Draft" &&
getData['items'][i]['masterDataObjectCode'] == objectCode) {
items = getData['items'][i];
print(items["controlType"]+" "+items["name"]);
setState(() {
observation = true;
number = 2;
getMasterDatas(items["controlType"], getData['items'][i]['masterDataObjectCode']);
});
}
}
} else {
print(error);
}
}
#override
void dispose() {
controllers.clear();
super.dispose();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery
.of(context)
.size;
return Scaffold(
appBar: AppBar(
title: const Text('New Observation'),
backgroundColor: appBar,
),
/*body: Container(
padding: const EdgeInsets.only(left: 20, right: 20),
decoration: BoxDecoration(
color: Color(0xFFF5F5F6),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
padding: EdgeInsets.only(top: 10),
itemCount: _Widget.length,
itemBuilder: (context, index) {
Widget widget = _Widget.elementAt(index);
return widget;
})
)
],
),*/
body: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
Container(
height: double.infinity,
color: bg,
child: PageView(
onPageChanged: (index) => setState(() {
pageNumber = index;
}),
controller: pageController,
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 16, bottom: 70, right: 16, top: 30),
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.only(top: 10),
itemCount: _Widget.length,
itemBuilder: (context, index) {
Widget widget = _Widget.elementAt(index);
return widget;
})
),
],
),
),
if(observation)
Container(
padding: EdgeInsets.only(left: 16, bottom: 70, right: 16, top: 30),
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.only(top: 10),
itemCount: _ObservationDetailsWidget.length,
itemBuilder: (context, index) {
Widget widget = _ObservationDetailsWidget.elementAt(index);
return widget;
})
)*/
]
)
),
Container(
padding: EdgeInsets.only(left: 16, bottom: 70, right: 16, top: 30),
child: SingleChildScrollView(
padding: EdgeInsets.only(bottom: 60),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
padding: EdgeInsets.all(20),
decoration: boxDecoration(
showShadow: true,
bgColor: Colors.white,
radius: 8,
color: border),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset("images/app/icons/upload.png", width: 50,),
SizedBox(height: 10,),
Text(uploadFile, style: TextStyle(fontSize: 15),),
SizedBox(height: 10,),
Container(
decoration: boxDecoration(
showShadow: true,
bgColor: textColor,
radius: 8,
color: border),
child: RaisedButton(
onPressed: () {},
color: textColor,
child: Text(
"Upload Files",
style: TextStyle(color: Colors.white),
),
),
)
],
),
)
],
),
),
),
],
),
),
Container(
margin: EdgeInsets.only(left: 16, right: 16, bottom: 20),
padding: EdgeInsets.only(left: 20, right: 20),
width: size.width,
height: 50,
decoration: BoxDecoration(color: textColor, borderRadius: BorderRadius.circular(15.0)),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.white,
radius: 15,
child: Text('${pageNumber + 1}', style: primaryTextStyle(size: 16, color: textColor)),
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: buildDotIndicator(),
),
pageNumber != number
? FlatButton(
onPressed: () {
pageController.nextPage(duration: Duration(milliseconds: 250), curve: Curves.fastOutSlowIn);
},
child: Text("Next", style: primaryTextStyle(size: 16, color: opBackgroundColor)),
)
: FlatButton(
onPressed: () {
finish(context);
},
child: Text("Submit", style: primaryTextStyle(size: 16, color: opBackgroundColor)),
)
],
),
),
],
),
);
}
retrive() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final String _token = prefs.getString(TOKEN);
setState(() => token = _token);
print(token);
setState(() {
// getMemberList();
getOrganizationDatas();
getObsProperty();
/*getMasterDatas();*/
});
}
Widget masterDropDownBox(var code) {
var radiolist = common.where((element) => element.id == code).toList();
_Widget.add(dynamicText(radiolist[0].masterDataObjectValue, textColor: textColor));
return Container(
margin: const EdgeInsets.only(top:0, left: 0, right: 20),
padding: const EdgeInsets.only(top:0, left: 10, right: 10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
border: Border.all(
color: headerColor,
width: 2
),
color: Colors.white),
child: Column(
children: <Widget>[
new DropdownButton(
isExpanded: true,
iconEnabledColor: headerColor,
iconDisabledColor: headerColor,
iconSize: 40,
dropdownColor: Colors.white,
hint: new Text("Select Tanent", style: TextStyle(color: headerColor),),
items: radiolist.map((e) {
return new DropdownMenuItem(
child: new Text(e.value.toUpperCase(), style: TextStyle(color: headerColor),),
value: e.value.toString(),);
}).toList(),
onChanged: (newvalue) {
setState(() {
positionSelection = newvalue;
});
},
value: positionSelection,)
],
)
);
}
save(String key, String value) async{
prefs = await SharedPreferences.getInstance();
prefs.setString(key, value);
}
retriveMaster(String key) async{
SharedPreferences prefs = await SharedPreferences.getInstance();
final String value = prefs.getString(key);
return value;
}
Widget multiSelect(var code){
var radiolist = common.where((element) => element.id == code).toList();
_Widget.add(dynamicText(radiolist[0].masterDataObjectValue, textColor: textColor));
return Container(
height: 200,
decoration: boxDecoration(
showShadow: false,
bgColor: ehs_white,
radius: 8,
color: border),
child: MultiSelectBottomSheetField(
items: radiolist.map((e) => MultiSelectItem(e.value, e.value)).toList(),
listType: MultiSelectListType.CHIP,
searchable: true,
decoration: boxDecoration(
showShadow: false,
bgColor: ehs_white,
radius: 8,
color: border),
onConfirm: (values) {
setState(() {
_selectedValues = values;
});
},
chipDisplay: MultiSelectChipDisplay(
chipColor: Colors.black,
textStyle: TextStyle(color: Colors.red),
items: _selectedValues.map((e) => MultiSelectItem(e, e.value)).toList(),
onTap: (value) {
setState(() {
_selectedValues.remove(value);
});
},
),
),
);
}
Widget multiSelections(var code) {
return Wrap(
spacing: 8,
direction: Axis.horizontal,
children: filterChipsList(code),
);
}
List<Widget> filterChipsList(var code){
List<Widget> chips = [];
var radiolist = common.where((element) => element.id == code).toList();
_ObservationDetailsWidget.add(dynamicText(radiolist[0].masterDataObjectValue, textColor: textColor));
for(int i = 0; i < radiolist.length; i++){
MultiSelectionModel multiSelectionModel = new MultiSelectionModel(radiolist[i].value, radiolist[i].id, radiolist[i].masterDataObjectValue, radiolist[i].controlIds, false);
_multiSelection.add(multiSelectionModel);
}
for (int i = 0; i < _multiSelection.length; i++) {
Widget item = Padding(
padding: const EdgeInsets.only(left: 10, right: 5),
child: FilterChip(
label: Text(_multiSelection[i].value),
labelStyle: const TextStyle(color: Colors.white,fontSize: 16),
backgroundColor: Colors.grey,
selected: _multiSelection[i].isSelected,
onSelected: (bool value) {
setState(() {
print(value);
_multiSelection[i].isSelected = value;
});
},
),
);
chips.add(item);
}
return chips;
}
} ```
I believe I am having issues with using setState in a futurebuilder - but Im not sure how to change this? Below you can see I am building a listView using a futureBuilder (http request to api) and connecting it to my ProjectModel model. From here I filter the values I need into List<ProjectSearch> searchList. What I am finding is when I try to implement a search box to filter through the objects I believe the setState is causing the futurebuilder to rebuild the page each time causing duplications. How can I separate the futurebuilder from the listView so that it only displays the one list object as the user types?
class _HomePageState extends State<HomePage> {
TextEditingController controller = TextEditingController();
late final Future<ProjectModel> futureProjects;
List<ProjectSearch> searchList = [];
List<ProjectSearch> finder = [];
var jobNames = [];
var jobNumbers = [];
var techs = [];
var pms = [];
var address = [];
var majors = [];
var budget = [];
#override
void initState() {
super.initState();
futureProjects = fetchProjects();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Upcoming/Live Projects',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
backgroundColor: ColorConstants.darkScaffoldBackgroundColor,
),
drawer: const CustomDrawer(),
backgroundColor: ColorConstants.lightScaffoldBackgroundColor,
body: Center(
child: FutureBuilder<ProjectModel>(
future: futureProjects,
builder: (context, snapshot) {
// finder.clear();
if (snapshot.hasData) {
var data = snapshot.data!;
var columns = data.columns;
var rows = data.rows;
for (var item in rows!) {
var cells = item.cells;
for (var elements in cells!) {
if (elements.columnId != null) {
if (elements.columnId == 2057691532158852) {
var displayValues = elements.displayValue;
if (displayValues != null) {
jobNames.add(displayValues);
}
if (displayValues == null) {
pms.removeLast();
techs.removeLast();
address.removeLast();
majors.removeLast();
budget.removeLast();
}
}
if (elements.columnId == 697505454286724) {
var projectNumber = elements.displayValue;
if (projectNumber != null) {
jobNumbers.add(projectNumber);
}
}
if (elements.columnId == 7452904895342468) {
var techAssigned = elements.displayValue;
if (techAssigned != null) {
if (techAssigned == 'ts#ag.com.au') {
techAssigned = 'Ts';
techs.add(techAssigned);
} else {
techs.add(techAssigned);
}
}
if (techAssigned == null) {
techAssigned = 'No tech assigned as yet';
techs.add(techAssigned);
}
}
if (elements.columnId == 2949305267971972) {
var pmName = elements.displayValue;
if (pmName != null) {
pms.add(pmName);
}
if (pmName == null) {
pmName = 'No project manager allocated';
pms.add(pmName);
}
}
if (elements.columnId == 5201105081657220) {
var addressValue = elements.displayValue;
if (addressValue != null) {
address.add(addressValue);
}
if (addressValue == null) {
addressValue = '';
address.add(addressValue);
}
}
if (elements.columnId == 52961559766916) {
var majorValue = elements.displayValue;
if (majorValue != null) {
majors.add(majorValue);
}
if (majorValue == null) {
majorValue = 'No';
majors.add(majorValue);
}
}
if (elements.columnId == 4226807856686980) {
var budgetHours = elements.displayValue;
if (budgetHours != null) {
budget.add(budgetHours);
}
if (budgetHours == null) {
budgetHours = 'TBA';
budget.add(budgetHours);
}
}
}
}
}
int index = 0;
for (int i = 0; i < jobNames.length; i++) {
// List<ProjectSearch> innerMap = [];
ProjectSearch myProjects = ProjectSearch(
address: jobNames[index],
budget: budget[index],
jobNumber: jobNumbers[index],
major: majors[index],
name: jobNames[index],
pM: pms[index],
tech: techs[index]);
index++;
searchList.add(myProjects);
}
return Container(
child: Column(
children: <Widget>[
Padding(
padding:
const EdgeInsets.only(left: 20, top: 20, right: 20),
child: TextField(
textAlign: TextAlign.center,
controller: controller,
onChanged: search,
keyboardType: const TextInputType.numberWithOptions(
signed: true),
// keeps going....
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: finder.length,
itemBuilder: (context, index) {
// print(finder.length);
final projectData = finder[index];
return MaterialButton(
onPressed: () => showModalBottomSheet<void>(
backgroundColor: Colors.transparent,
context: context,
builder: (BuildContext context) {
return ClipRRect(
borderRadius: const BorderRadius.only(
topRight: Radius.circular(27.0),
topLeft: Radius.circular(27.0)),
child: Container(
height: 1000,
color: ColorConstants
.secondaryDarkAppColor,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Container(
height: 400,
margin: const EdgeInsets.only(
top: 20,
left: 20,
right: 20),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment
.spaceAround,
children: [
const Padding(
padding:
EdgeInsets.only(
top: 10.0,
bottom: 5.0)),
const Center(
child: Text(
'Project Details',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight:
FontWeight
.w700),
),
),
Row(
children: [
const Text(
'Project: ',
style: TextStyle(
color: Colors
.white70,
fontWeight:
FontWeight
.w600,
fontSize: 17),
),
const SizedBox(
width: 20),
Flexible(
child: Padding(
padding:
const EdgeInsets
.symmetric(
horizontal:
8.0),
child: Text(
projectData.name,
overflow:
TextOverflow
.ellipsis,
maxLines: 2,
style: const TextStyle(
color: Colors
.white,
fontWeight:
FontWeight
.w600,
fontSize: 17),
),
),
),
],
),
],
),
),
);
},
),
child: Container(
height: 50,
margin: const EdgeInsets.only(
top: 30, left: 20, right: 20),
decoration: const BoxDecoration(
color: ColorConstants
.darkScaffoldBackgroundColor,
borderRadius:
BorderRadius.all(Radius.circular(8)),
),
padding: const EdgeInsets.all(15),
child: Center(
child: Text(
projectData.name,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 17),
),
),
),
);
}),
),
],
),
);
} else if (snapshot.hasError) {
print(snapshot);
return Text(
'${snapshot.error}',
style: const TextStyle(color: Colors.white),
);
} else {
return const CircularProgressIndicator();
}
}),
),
);
}
void search(String query) {
final suggestions = searchList.where((search) {
final projectName = search.name.toLowerCase();
final input = query.toLowerCase();
return projectName.contains(input);
}).toList();
setState(() {
finder.clear();
finder = suggestions;
});
}
}
Here is what my UI looks like after searching....
Inside your FutureBuilder's builder, try this:
searchList = [];// <---- add this
int index = 0;
for (int i = 0; i < jobNames.length; i++) {
// List<ProjectSearch> innerMap = [];
ProjectSearch myProjects = ProjectSearch(
address: jobNames[index],
budget: budget[index],
jobNumber: jobNumbers[index],
major: majors[index],
name: jobNames[index],
pM: pms[index],
tech: techs[index]);
index++;
searchList.add(myProjects);
}
and also because when every time keyboard status change your FutureBuilder rebuild again do this:
var data = snapshot.data!;
var columns = data.columns;
var rows = data.rows;
jobNames = [];
jobNumbers = [];
techs = [];
pms = [];
address = [];
majors = [];
budget = [];
for (var item in rows!) {
var cells = item.cells;
for (var elements in cells!) {
...
}
}
define the future in the build and use it once like this:
..
Widget build(BuildContext context) {
Future<ProjectModel> futureProjects = fetchProjects() ;
...
Then remove it in the initState() and use it in the future builder like you've done. Refer to this and read more on when to use initSate() and when to use FutureBuilder()
About your Query search: Try removing the setState() in the search method
void search(String query) {
final suggestions = searchList.where((search) {
final projectName = search.name.toLowerCase();
final input = query.toLowerCase();
return projectName.contains(input);
}).toList();
}
}
I was converting the following below ui to code.
I didn't find a suitable package for it, im stepper also didn't have the ability to customize in this way.
So I tried to use listView.builder.
Now I don't know how to add the next and previous buttons.
so that the number inside the scroll view scrolls like the picture below and is placed in the view area.
If you know a suitable package, introduce it.
my code:
FadingEdgeScrollView.fromScrollView(
gradientFractionOnEnd: 0.2,
gradientFractionOnStart: 0.15,
child: ListView.builder(
controller: _controller2,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
int one = index + 1;
int two = 0;
Color colorWhat(int q) {
Color color;
if (q == two) {
color = Color(0xff0AFF6C);
} else {
color = Colors.white;
}
return color;
}
double sizeOfCircle(int qq) {
int size;
if (qq == 0) {
size = 27;
} else {
size = 22;
}
return size.toDouble();
}
double sizeOfCircleText(int qqq) {
double size;
if (qqq < 10) {
size = 13.9;
} else {
size = 13.7;
}
return size;
}
return GestureDetector(
child: Row(
children: [
Container(
alignment: Alignment.center,
width: sizeOfCircle(index),
// height: sizeOfCircle(index),
// padding: EdgeInsets.all(sizeOfCircle(index)),
margin: const EdgeInsets.fromLTRB(
2, 0, 17, 0),
decoration: BoxDecoration(
color: colorWhat(index),
shape: BoxShape.circle,
boxShadow: const [
BoxShadow(
offset: Offset(0, 5),
blurRadius: 10.0,
spreadRadius: -7,
),
],
),
child: Text(
one.toString(),
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: sizeOfCircleText(index),
),
),
),
],
),
onTap: () =>
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text((index+1).toString()),
),
),
);
},
itemCount: 100,
),
),
first select a current index like this:
int currentPageIndex = 0;
and then on tap function. Write a code like this
for decrement...
if (currentPageIndex == 4) {
return;
}
setState(() {
currentPageIndex += 1;
});
for Increment...
if (currentPageIndex == 4) {
return;
}
setState(() {
currentPageIndex += 1;
});
Change your text...
Text(
'${index + 1}'
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: sizeOfCircleText(index),
),
),
and change your onTap function like this:
onTap: () {
setState(() {
currentPageIndex = index;
});
},
Keyboard triggers the api calling while closing and opening
I have search bar I didn't pass anything inside the search bar but when I click the search bar The api call will run.
I don't know why that thing was happen I tried several ways but It won't work
Even Inside the keyboard I choose the one hand keyboard that time also api will run
Also tried the Focusnode also.
class PopupNaviagator extends StatefulWidget {
var body;
String leadsName = "";
Map<String, dynamic> listValues;
PopupNaviagator(this.listValues);
var data;
String pageData = "";
double totalPageCount = 0;
int pageIncrementer = 1;
#override
_PopupNavigatorState createState() => _PopupNavigatorState();
}
class _PopupNavigatorState extends State<PopupNaviagator> {
Utils util = new Utils();
bool isSearching = false;
#override
void initState() {
super.initState();
}
String searchingText = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: util.getColors(1001),
stops: [0.1, 5.0],
),
),
),
title: !isSearching
? Text("Select Search Type")
: TextField(
autofocus: true,
autocorrect: true,
onChanged: (value) {
searchingText = value;
},
cursorColor: Colors.white,
onSubmitted: (value) {
searchingText = value;
campaignAPI(
widget.listValues["colname"].toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
},
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
icon: Icon(Icons.search),
hintText: "Search ",
hintStyle: TextStyle(color: Colors.white)),
),
actions: <Widget>[
isSearching
? IconButton(
icon: Icon(Icons.cancel),
onPressed: () {
setState(() {
searchingText = "";
this.isSearching = false;
campaignAPI(
widget.listValues["colname"].toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
/* filteredCountries = countries;*/
});
},
)
: IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
this.isSearching = true;
});
},
)
],
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5))),
child: Scaffold(
body: FutureBuilder(
future: campaignAPI(widget.listValues["colname"].toString(), "1",
searchingText, 0),
builder: (context, snapshot) {
if (snapshot.hasData) {
var body;
if (widget.data == null) {
body = snapshot.data;
} else {
body = widget.data;
}
final records = body["list_records"];
widget.pageData = body["PageValues"];
widget.totalPageCount =
(body["TotalRecordCount"] / 5).toDouble();
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (records.length != 0) ...[
Expanded(
child: ListView.builder(
padding: EdgeInsets.only(
top: 0,
bottom: 0,
),
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: records.length,
itemBuilder: (context, index) {
Map<String, dynamic> pickerValues =
records[index];
String titleName =
pickerValues["viewcol_value"]
.toString();
return Container(
margin: const EdgeInsets.all(5.00),
decoration: new BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.grey, width: 1.0),
borderRadius: new BorderRadius.all(
Radius.circular(3.0)),
),
child: FlatButton(
padding: EdgeInsets.all(8.0),
onPressed: () {
setState(() {
List<String> strArr = [
titleName,
pickerValues["rec_id"].toString(),
widget.listValues["colname"]
];
Navigator.pop(context, strArr);
});
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(titleName.toString()),
Icon(
Icons.check_circle_outlined,
color: Colors.grey,
),
]),
),
);
}),
),
] else ...[
Container(
height: MediaQuery.of(context).size.height / 1.4,
child: Center(
child: Container(
padding: EdgeInsets.all(65),
child: Text(
"No Record Found",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.black),
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
width: 2,
),
)),
),
),
],
if (records.length != 0) ...[
Container(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
if (widget.pageIncrementer > 1) {
widget.pageIncrementer--;
campaignAPI(
widget.listValues["colname"]
.toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
setState(() {});
} else {
util.showToast("No records to show");
}
},
child: Icon(Icons.arrow_left_rounded,
size: 50, color: Colors.white),
),
Text(
widget.pageData,
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold),
),
InkWell(
onTap: () {
if (widget.totalPageCount > 1 &&
widget.totalPageCount >=
widget.pageIncrementer) {
widget.pageIncrementer++;
campaignAPI(
widget.listValues["colname"]
.toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
} else {
util.showToast("No reocrds to show");
}
},
child: Icon(Icons.arrow_right_rounded,
size: 50, color: Colors.white),
),
],
),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: util.getColors(1001),
stops: [0.1, 5.0],
),
),
)
]
],
),
),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error.toString()}');
}
return Center(
child: CircularProgressIndicator(),
);
},
),
),
));
}
campaignAPI(
String field_col, String page_no, String searchValue, int flag) async {
Utils util = new Utils();
SharedPreferences prefs = await SharedPreferences.getInstance();
final accessKey = prefs.getString('access_key');
final companyName = prefs.getString('company_name');
Object requestParam = {
"companyname": companyName,
"access_key": accessKey.toString(),
"field_col": field_col,
"page_no": page_no,
"searchValue": searchValue,
};
print(requestParam.toString());
APIS apis = new APIS();
Uri url = Uri.parse(apis.searchquickcreate);
util.prints(url);
util.prints(requestParam);
final response = await http.post(url, body: requestParam);
if (response.statusCode == 200) {
final body = json.decode(response.body);
print(body);
String status = body["status"];
if (status != "failed") {
if (flag == 1) {
setState(() {
widget.data = body;
});
}
return body;
} else {
util.logOut(context);
return body;
}
} else {
Navigator.pop(context);
util.showToast("Server Error !");
throw Exception("Server Error !");
}
}
}
I'm trying to implement a button animation when on clicked it shrinks and shows the circular progress indicator (while loading) then expands and shows the result of the executed operation (in this case it is login).
The code idea came from this link. The design idea came from this link. Now I implemented this before and it worked exactly as it was supposed to. However when implementing it again here, on button pressed -> the person logs in successfully and the button changes color as per design an all. The only problem is that the button animation does not happen. I tried printing the values of the _loginButtonWidth and can actually see it decreasing and increasing as per design, but visually the width stays the same.
Code:
import 'package:flutter/material.dart';
import 'package:garuda_academy_app/Login/Authentication.dart';
import 'package:garuda_academy_app/Tools/FixedColors.dart';
import 'dart:async';
class LoginPage extends StatefulWidget {
LoginPage({this.auth, this.onLoggedIn});
#override
_LoginPageState createState() => _LoginPageState();
final BaseAuth auth;
final VoidCallback onLoggedIn;
}
class _LoginPageState extends State<LoginPage> with TickerProviderStateMixin {
// for device type
bool _isIos;
// text form field
String _userEmail = "";
String _userPassword = "";
final _formKey = GlobalKey<FormState>();
// for login button
int _loginButtonState = 0;
double _loginButtonWidth = double.maxFinite;
Color _loginButtonColor = primaryColor;
Color _loginButtonOutlineColor = primaryColor;
Color _loginButtonTextColor = secondaryColor;
GlobalKey _loginButtonKey = GlobalKey();
Animation _loginButtonAnimation;
AnimationController _loginButtonController;
Widget _loginButton() {
if (_loginButtonState == 0) {
return Text(
"Log In",
style: TextStyle(
color: _loginButtonTextColor,
fontSize: 20,
),
);
} else if (_loginButtonState == 1) {
return CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(secondaryColor),
);
} else if (_loginButtonState == 2) {
return Icon(
Icons.check,
color: _loginButtonTextColor,
);
} else if (_loginButtonState == 3) {
return Icon(
Icons.close,
color: _loginButtonTextColor,
);
} else if (_loginButtonState == 4) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.check,
color: _loginButtonTextColor,
),
Icon(
Icons.check,
color: transparent,
),
Text(
"Successful",
style: TextStyle(
color: _loginButtonTextColor,
),
),
],
);
} else if (_loginButtonState == 5) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.close,
color: _loginButtonTextColor,
),
Icon(
Icons.close,
color: transparent,
),
Text(
"Unsuccessful",
style: TextStyle(
color: _loginButtonTextColor,
),
),
],
);
}
}
bool _validateLoginAndSave() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
return true;
}
return false;
}
_animateLoginButton() async {
String userId = "";
String errorMsg = "";
setState(() {
_loginButtonState = 1;
});
// animation
double initialWidth = _loginButtonKey.currentContext.size.width;
_loginButtonController =
AnimationController(duration: Duration(milliseconds: 300), vsync: this)
..addStatusListener((AnimationStatus status) async {
if (status == AnimationStatus.completed) {
// firebase signin
try {
userId = await widget.auth.signIn(_userEmail, _userPassword);
} catch (e) {
setState(() {
errorMsg = _isIos ? e.details : e.message;
print(errorMsg);
});
}
// loading timer
Timer(Duration(seconds: 1), () {
// set login state
_loginButtonState =
(userId.length > 0 && userId != null) ? 2 : 3;
// change colors
if (_loginButtonState == 2) {
_loginButtonColor = secondaryColor;
_loginButtonOutlineColor = successfulColor;
_loginButtonTextColor = successfulColor;
} else if (_loginButtonState == 3) {
_loginButtonColor = secondaryColor;
_loginButtonOutlineColor = unsuccessfulColor;
_loginButtonTextColor = unsuccessfulColor;
}
_loginButtonController.reverse();
});
} else if (status == AnimationStatus.dismissed) {
if (_loginButtonState == 2) {
_loginButtonState = 4;
} else if (_loginButtonState == 3) {
_loginButtonState = 5;
}
// minimal time before it is done
Timer(Duration(seconds: 1), () {
setState(() {
if (_loginButtonState == 4) widget.onLoggedIn();
// reset state
_loginButtonState = 0;
// reset colors
_loginButtonColor = primaryColor;
_loginButtonOutlineColor = primaryColor;
_loginButtonTextColor = secondaryColor;
});
});
}
});
_loginButtonAnimation =
Tween(begin: 0.0, end: 1.0).animate(_loginButtonController)
..addListener(() {
setState(() {
_loginButtonWidth = initialWidth -
((initialWidth - 80.0) * _loginButtonAnimation.value);
});
print("initial: " + initialWidth.toString());
print("current: " + _loginButtonWidth.toString());
});
_loginButtonController.forward();
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
_isIos = Theme.of(context).platform == TargetPlatform.iOS;
return Scaffold(
resizeToAvoidBottomInset: false,
body: SingleChildScrollView(
child: Center(
child: Theme(
data: ThemeData(primaryColor: primaryColor),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Padding(
padding: EdgeInsets.all(40),
child: Text(
"Log in to continue",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: primaryColor,
),
),
),
Padding(
padding: EdgeInsets.only(bottom: 20, left: 40, right: 40),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
style: TextStyle(
fontSize: 20,
),
decoration: InputDecoration(
labelText: "Email Address",
labelStyle: TextStyle(fontSize: 20),
),
validator: (value) =>
value.isEmpty ? "Email cannot be empty" : null,
onSaved: (value) => _userEmail = value,
),
),
Padding(
padding: EdgeInsets.only(bottom: 20, left: 40, right: 40),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
obscureText: true,
style: TextStyle(
fontSize: 20,
),
decoration: InputDecoration(
labelText: "Password",
labelStyle: TextStyle(fontSize: 20),
),
validator: (value) =>
value.isEmpty ? "Password cannot be empty" : null,
onSaved: (value) => _userPassword = value,
),
),
Padding(
padding: EdgeInsets.only(bottom: 50, left: 40, right: 40),
child: Container(
height: 60,
width: _loginButtonWidth,
child: PhysicalModel(
color: transparent,
borderRadius: BorderRadius.circular(10.0),
child: RaisedButton(
elevation: 8.0,
color: _loginButtonColor,
key: _loginButtonKey,
shape: OutlineInputBorder(
borderSide: BorderSide(
color: _loginButtonOutlineColor,
),
borderRadius: BorderRadius.circular(10.0),
),
child: _loginButton(),
onPressed: () {
setState(() {
if (_loginButtonState == 0 &&
_validateLoginAndSave()) {
_animateLoginButton();
}
});
},
),
),
),
),
],
),
),
),
),
),
);
}
}
Button width stays the same when it is supposed to shrink:
Easy fix, add a Center or Align widget as a parent of your Container button.
Padding(
padding: EdgeInsets.only(bottom: 50, left: 40, right: 40),
child: Center(
child: Container(
height: 60,
width: _loginButtonWidth,
To get more info check Layout Behavior