DropdownSearch<T>(
dropdownBuilder: (context, data) {
return AutoSizeText(
displayProperty(data) ?? "",
maxLines: 1,
style: const TextStyle(fontWeight: FontWeight.w400, fontSize: 16),
);
},
popupProps: PopupProps.menu(
fit: FlexFit.loose,
// showSelectedItems: true,
// interceptCallBacks: true,
itemBuilder: popupItemBuilder ??
(context, data, selected) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.black12)),
),
child: ListTile(
title: Text(
displayProperty(data) ?? "",
maxLines: 1,
style: AppTheme.subtitle1,
),
),
);
},
showSearchBox: showSearchBox,
emptyBuilder: (context, data) => Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text("No Data in $label was found."),
),
),
),
asyncItems: (String? data) => getData(),
// focusNode: focusNode,
onSaved: onSaved,
selectedItem: value,
validator: !isRequired
? null
: validator ??
(value) => value == null ? "$label can't be empty" : null,
// mode: Mode.MENU,
// showClearButton: enable,
key: keyX,
enabled: enable,
// maxHeight: maxHeight,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
labelText: label,
errorMaxLines: 2,
isDense: false,
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black45)),
// border: const OutlineInputBorder(),
errorBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightGreen),
),
),
),
itemAsString: (data) => displayProperty(data) ?? "",
onChanged: onChanged,
);
I added mine like this and it worked.
DropdownSearch<dynamic>(
popupProps: const PopupProps.menu(
showSearchBox: true,
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
border: OutlineInputBorder(),
contentPadding:
EdgeInsets.fromLTRB(12, 12, 8, 0),
hintText: "search staff...",
),
)),
its empty because you build the field with empty string.
displayProperty(data) ?? "", this is return empty string when data is null.
DropdownSearch<T>(
dropdownBuilder: (context, data) {
return AutoSizeText(
displayProperty(data) ?? "your Hint Text here",
maxLines: 1,
style: const TextStyle(fontWeight: FontWeight.w400, fontSize: 16),
);
},
.......
UPDATE
if you want to add hint text on popup search field you can add this to you code
searchBoxDecoration: InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.fromLTRB(12, 12, 8, 0),
hintText: "hint goes here",
)
you can found it from plugin owner : https://github.com/salim-lachdhaf/searchable_dropdown/issues/138#issuecomment-808702346
Related
How do I properly align the prefix icon, the hintText, the actual value that the user has typed in and the suffix icon? I am using textformfield for this one.
Widget yourNameWidget(yourNameCtrlr) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 0.0),
child: TextFormField(
style: const TextStyle(fontFamily: 'Poppins', fontSize: 12),
controller: yourNameCtrlr,
keyboardType: TextInputType.text,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(18),
isDense: true,
prefixIcon: const Icon(Icons.person),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xFFCECECE)),
borderRadius: BorderRadius.circular(12),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFCECECE)),
),
// this does not align with the prefix and the hint text
suffix: GestureDetector(
onTap: () {
yourNameCtrlr.clear();
},
child: const Icon(
Icons.clear,
size: 16,
),
),
hintText: 'Your Name',
fillColor: const Color(0xFFFEFEFE),
filled: true,
),
validator: (value) {
if (value!.isEmpty || !RegExp(r'^[a-z A-Z]+$').hasMatch(value)) {
return "Please enter a valid name.";
} else {
return null;
}
},
onChanged: (value) {},
),
);
}
I want the three of it (prefix,hint text, suffix) should be aligned.
Here is the image for the preview of the textformfield
https://prnt.sc/BxYxnZx1G5od
I was used this type of textformfield please see the reference below:
TextFormField(
controller: textEditingController,
cursorColor: AppTheme.secondaryColor,
autofocus: true,
onChanged: (txt) {
},
style: const TextStyle(
fontSize: 16.0, color:
Color.fromARGB(255,4,4,4)),
decoration: InputDecoration(
border: InputBorder.none,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(
color: AppTheme.secondaryColor_30,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(
color: AppTheme.secondaryColor_30,
),
),
hintText:
StringConstants.searchForAGroupOrFriend,
hintStyle: Theme.of(context)
.textTheme
.caption!
.copyWith(color: AppTheme.grey2),
fillColor: AppTheme.secondaryColor_10,
contentPadding: const EdgeInsets.only(top: 10),
filled: true,
prefixIcon: GestureDetector(
onTap: () {
},
child: Image.asset(
Assets.icBackRound,
scale: 3.5,
color: AppTheme.backDarkGrey,
),
),
suffixIcon: GestureDetector(
child: Image.asset(
Assets.searchIcon,
color: AppTheme.secondaryColor,
scale: 3.5,
),
onTap: () {
},
),
),
),
I am using country_picker for drop-down-menu.
And I need to reduce height of this menu. How can I do this?
And how to get border to showCountryPicker?
This is what I want
And this what I get
I tried to add bottomSheetHeight, but it hides my bottom buttons.
And without bottomSheetHeigh the drop-down-menu is in full screen mode
This is my code:
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12),
child: TextFormField(
controller: _country,
readOnly: true,
onTap: () {
showCountryPicker(
context: context,
showWorldWide: false,
showPhoneCode: false,
showSearch: false,
countryListTheme: CountryListThemeData(
backgroundColor: AppColors.backgroundColor,
borderRadius: BorderRadius.circular(8),
bottomSheetHeight: 380,
flagSize: 0,
textStyle: TextStyle(
color: AppColors.grayA0A0A0,
fontSize: 18,
height: 2.0
)
),
onSelect: (Country country) {
log(country.toString());
}
);
},
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(width: 0)),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(width: 1, color: AppColors.darkGray),
borderRadius: BorderRadius.circular(10)),
hintText: "Choose a country",
hintStyle: const TextStyle(
color: AppColors.grayA0A0A0, fontWeight: FontWeight.w500),
filled: true,
fillColor: AppColors.lightDark,
contentPadding:
const EdgeInsets.only(left: 8, bottom: 20, top: 20),
prefixIcon: InkWell(
child: SvgPicture.asset(
"assets/icons/Country.svg",
color: AppColors.grayA0A0A0,
height: 14,
width: 18,
fit: BoxFit.scaleDown,
),
),
suffixIcon: InkWell(
child: SvgPicture.asset(
"assets/icons/arrow_down.svg",
color: AppColors.grayA0A0A0,
height: 14,
width: 18,
fit: BoxFit.scaleDown,
),
)
),
),
),
),
Row(
children: <Widget>[
Expanded(
flex: 1,
//SizedBox(height: 20.0),
child: CountryPicker(
dense: true,
showFlag: false, //displays flag, true by default
showDialingCode:
true, //displays dialing code, false by default
showName: true, //displays country name, true by default
showCurrency: false, //eg. 'British pound'
showCurrencyISO: false,
onChanged: (Country country) {
setState(() => _selected = country);
print(country.dialingCode);
countryCode = country.dialingCode;
},
selectedCountry: _selected,
),
),
Expanded(
flex: 3,
//SizedBox(height: 20.0),
child: TextFormField(
decoration: InputDecoration(
labelText: 'Mobile no.',
border: OutlineInputBorder(),
),
validator: (val) => val.length != 10
? 'Enter a mobile number of 10 digits'
: null,
onChanged: (val) {
setState(() => phone = val);
phoneno = phone;
},
),
),
],
),
I'm trying to make the phone number field in the design. I'm using the intl_phone_number_input package for this but I couldn't do it like in my design.
I would be glad if you can help with this.
My design:
My Output:
My code:
InternationalPhoneNumberInput(
hintText: 'Telefon Numarası',
onInputChanged: (PhoneNumber number) {
print(number.phoneNumber);
},
onInputValidated: (bool value) {
print(value);
},
ignoreBlank: false,
autoValidateMode: AutovalidateMode.disabled,
selectorTextStyle: TextStyle(
color: Colors.black,
backgroundColor: Colors.grey,
),
selectorConfig: const SelectorConfig(
selectorType: PhoneInputSelectorType.DROPDOWN,
setSelectorButtonAsPrefixIcon: true,
leadingPadding: 0,
showFlags: false,
trailingSpace: false),
initialValue: PhoneNumber(isoCode: 'TR'),
textFieldController: TextEditingController(),
formatInput: false,
keyboardType: TextInputType.numberWithOptions(
signed: true, decimal: true),
inputBorder: UnderlineInputBorder(),
inputDecoration: InputDecoration(
floatingLabelAlignment: FloatingLabelAlignment.start,
labelText: 'Telefon Numarası',
),
textStyle: AppTextStyle().getSfProDisplayMedium(Colors.black),
onSaved: (PhoneNumber number) {
print('On Saved: $number');
},
),
I think we can use a combination of two types widget, I try use Stack
And this is my UI:
My code:
Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Telefon Numarası',
style: TextStyle(color: Colors.grey),
),
Container(
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(width: 1, color: Colors.grey))
),
child: Stack(
children: [
Positioned(
bottom: 10,
top: 10,
left: 0,
child: Container(
height: 30,
width: 80,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(5),
),
child: Row(
children: const [
Spacer(),
Icon(CupertinoIcons.chevron_down, size: 16,),
SizedBox(width: 5,),
],
),
),
),
SizedBox(
height: 50,
child: InternationalPhoneNumberInput(
hintText: 'Telefon Numarası',
onInputChanged: (PhoneNumber number) {
print(number.phoneNumber);
},
onInputValidated: (bool value) {
print(value);
},
ignoreBlank: false,
autoValidateMode: AutovalidateMode.disabled,
selectorTextStyle: const TextStyle(
color: Colors.black,
),
selectorConfig: const SelectorConfig(
selectorType: PhoneInputSelectorType.BOTTOM_SHEET,
setSelectorButtonAsPrefixIcon: false,
leadingPadding: 10,
showFlags: false,
trailingSpace: true,
),
initialValue: PhoneNumber(isoCode: 'TR'),
textFieldController: TextEditingController(),
formatInput: false,
keyboardType: TextInputType.numberWithOptions(
signed: true, decimal: true),
inputDecoration: const InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent)
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent)
),
floatingLabelAlignment: FloatingLabelAlignment.start,
// labelText: 'Telefon Numarası',
),
textStyle: const TextStyle(color: Colors.black),
onSaved: (PhoneNumber number) {
print('On Saved: $number');
},
),
),
],
),
),
],
),
),
I have a login system working with Flutter, PHP, and SQL but I want to be able to display the errors (if any) as a Flushbar. The controller receives the error as (res["message"]) and i would like this to be displayed on the register page but i cant seem to get it to work
Here is the controller that is called on click
void register() async {
try {
var response = await http
.post(Uri.parse("http://noddospls/untitled/authentication/register.php"), body: {
"name" : nameTE.text,
"username": emailTE.text,
"password": passwordTE.text
});
print(response.body);
var res = json.decode(response.body);
var success = (res["success"]);
print (success);
if (formKey.currentState!.validate()) {
if (success == "false"){
//display error from api (res["message"])
} else if (success == "true") {
Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
builder: (context) => LogInScreen(),
),
);
}
}
}catch(e){
print(e);
}
}
and here is my page that the controller is called from
Widget build(BuildContext context) {
return FxBuilder<RegisterController>(
controller: controller,
builder: (controller) {
return Scaffold(
body: Padding(
padding: FxSpacing.fromLTRB(
20, FxSpacing.safeAreaTop(context) + 20, 20, 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FxText.h3(
'Sign up',
fontWeight: 700,
),
FxSpacing.height(20),
Form(
key: controller.formKey,
child: Column(
children: [
TextFormField(
style: FxTextStyle.b2(),
decoration: InputDecoration(
floatingLabelBehavior:
FloatingLabelBehavior.never,
filled: true,
isDense: true,
fillColor: customTheme.card,
prefixIcon: Icon(
FeatherIcons.user,
color: theme.colorScheme.onBackground,
),
hintText: "Name",
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
border: outlineInputBorder,
contentPadding: FxSpacing.all(16),
hintStyle: FxTextStyle.b2(),
isCollapsed: true),
maxLines: 1,
controller: controller.nameTE,
validator: controller.validateName,
cursorColor: theme.colorScheme.onBackground,
),
FxSpacing.height(20),
TextFormField(
style: FxTextStyle.b2(),
decoration: InputDecoration(
floatingLabelBehavior:
FloatingLabelBehavior.never,
filled: true,
isDense: true,
fillColor: customTheme.card,
prefixIcon: Icon(
FeatherIcons.mail,
color: theme.colorScheme.onBackground,
),
hintText: "Email Address",
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
border: outlineInputBorder,
contentPadding: FxSpacing.all(16),
hintStyle: FxTextStyle.b2(),
isCollapsed: true),
maxLines: 1,
controller: controller.emailTE,
validator: controller.validateEmail,
cursorColor: theme.colorScheme.onBackground,
),
FxSpacing.height(20),
TextFormField(
style: FxTextStyle.b2(),
decoration: InputDecoration(
floatingLabelBehavior:
FloatingLabelBehavior.never,
filled: true,
isDense: true,
fillColor: customTheme.card,
prefixIcon: Icon(
FeatherIcons.lock,
color: theme.colorScheme.onBackground,
),
hintText: "Password",
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
border: outlineInputBorder,
contentPadding: FxSpacing.all(16),
hintStyle: FxTextStyle.b2(),
isCollapsed: true),
maxLines: 1,
controller: controller.passwordTE,
validator: controller.validatePassword,
cursorColor: theme.colorScheme.onBackground,
),
FxSpacing.height(20),
TextFormField(
style: FxTextStyle.b2(),
decoration: InputDecoration(
floatingLabelBehavior:
FloatingLabelBehavior.never,
filled: true,
isDense: true,
fillColor: customTheme.card,
prefixIcon: Icon(
FeatherIcons.lock,
color: theme.colorScheme.onBackground,
),
hintText: "Re-type Password",
enabledBorder: outlineInputBorder,
focusedBorder: outlineInputBorder,
border: outlineInputBorder,
contentPadding: FxSpacing.all(16),
hintStyle: FxTextStyle.b2(),
isCollapsed: true),
maxLines: 1,
controller: controller.password2TE,
validator: controller.validatePassword,
cursorColor: theme.colorScheme.onBackground,
),
],
),
),
FxSpacing.height(24),
Row(
children: [
FxText.b3(
'By Signing up, you agree to our ',
fontSize: 11,
),
FxText.b3(
'Terms & Conditions',
color: customTheme.fitnessPrimary,
fontSize: 11,
),
],
),
FxSpacing.height(24),
Row(
children: [
FxButton(
padding: FxSpacing.xy(16, 12),
onPressed: () {
controller.register();
},
backgroundColor: customTheme.card,
splashColor:
theme.colorScheme.onBackground.withAlpha(40),
elevation: 0,
borderRadiusAll: 4,
child: Row(
children: [
Image(
image: AssetImage(Images.google),
height: 17,
width: 17,
),
FxSpacing.width(20),
FxText.l2(
'Login with Google',
fontWeight: 600,
color: theme.colorScheme.onBackground,
),
],
)),
FxSpacing.width(20),
Expanded(
child: FxButton(
padding: FxSpacing.y(12),
onPressed: () {
controller.register();
},
backgroundColor: customTheme.fitnessPrimary,
elevation: 0,
borderRadiusAll: 4,
child: FxText.b2(
'Continue',
color: customTheme.fitnessOnPrimary,
fontWeight: 600,
),
),
),
],
),
FxSpacing.height(20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FxText.b3(
'Already have an account? ',
),
InkWell(
onTap: () {
controller.goToLogInScreen();
},
child: FxText.b3(
'Log In',
color: customTheme.fitnessPrimary,
)),
],
),
],
),
),
);
});
}
}
Any help appreciated
I have a TextFormField to collect user authentication input, and it's pretty fine.
But when it shows the validation message, this happens:
How can I change the position of the error message to this do not happen anymore? I just want a way do easy fix this and the field still pretty.
Here is the code.
Form(
key: _formKey,
child: Container(
width: double.infinity,
height: 40,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 1.1,
color: Colors.black45,
spreadRadius: 0.5,
offset: Offset(
1.5,
2,
),
),
],
borderRadius: BorderRadius.circular(20),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: SizedBox(
height: 40,
child: TextFormField(
style: TextStyle(color: Colors.black),
decoration: InputDecoration(
border: InputBorder.none,
disabledBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
focusedBorder: InputBorder.none,
focusedErrorBorder: InputBorder.none,
hintText: 'Full name',
hintStyle: TextStyle(color: Colors.grey[600]),
icon: Icon(Icons.account_circle, color: Colors.black),
),
onSaved: (string) => _formData['name'] = string,
validator: (string) {
if (string.isEmpty) {
return 'Field can\'t be empty';
}
return null;
},
),
),
),
),
)
You can show error message below text field so that you UI won't disturb. You need to put TextFormField and Container with box decoration in a stack. Now when validator will show error message then container with not grow and gives an impression that error message is showing below TextFormField.
Stack(children: [
Container(
height: 48,
decoration: BoxDecoration(
color: Colors.grey.shade200,
borderRadius: BorderRadius.circular(30),
)),
TextFormField(
validator: (val) =>
val.length < 1 ? 'Name Required' : null,
onSaved: (val) => _username = val,
obscureText: false,
keyboardType: TextInputType.name,
controller: _controllerUsername,
autocorrect: false,
decoration: InputDecoration(
hintText: 'Name',
border: InputBorder.none,
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(30.0)),
borderSide: BorderSide(color: Colors.blue)),
contentPadding: EdgeInsets.symmetric(
vertical: 15, horizontal: 20),
),
),]
Just set the helper text like that:
TextFormField(
decoration: const InputDecoration(
helperText: ' ',
),
validator: myValidator,
),
You can check the below code.
Widget _buildEmailTextField()) {
return Container(
height: 35,
child: Theme(
data: new ThemeData(
primaryColor: Color(0xFF262C48),
primaryColorDark: Color(0xFF262C48),
),
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(
height: 20,
),
Container(
child: TextFormField(
keyboardType: TextInputType.emailAddress,
validator: (val) {
bool emailValid = RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+")
.hasMatch(val);
if (!emailValid) {
return 'Invalid Email Address';
} else {
return null;
}
},
controller: emailController,
readOnly: isLoading ? true : false,
decoration: InputDecoration(
fillColor: Color(0xFFd9d8d8),
filled: true,
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(7.0),
),
borderSide:
BorderSide(color: Color(0xFF262C48), width: 2.0)),
contentPadding: new EdgeInsets.symmetric(
vertical: 25.0, horizontal: 10.0),
// prefixIcon: Icon(
// Icons.email,
// color: Color(0xFF008577),
// ),
hintText: 'Email',
),
),
),
RaisedButton(
onPressed: () {
// Validate returns true if the form is valid, otherwise false.
if (_formKey.currentState.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
)
],
),
),
),
);
}
Just put a container as a parent of textfield can solve the error.
we create value like this
int testForPhoneNumber = 0;
and change this value to two cases
the first case if phone number (my exmaple) is validate I set the value to 0
the second case if phone number is not validate I set the value to 1
so I do this in code ==> (testForPhoneNumber == 0)? .... : ....,
the point is represent the same thing but I change this in
InputDecoration in first case : contentPadding: EdgeInsets.fromLTRB(10, 10, 10, 0),
in second case : contentPadding: EdgeInsets.fromLTRB(10, 50, 10, 0),
the points represent in the picture below
Note I change the top of text.
this is the code
https://drive.google.com/file/d/1v-THl1GBDl1oaVmNVao9ghRJaI2MjnMj/view?usp=sharing