Flutter Changing Widget's Properties - flutter

I have a widget that adding some decoration to out of the widget as the code below.I also wanted to change decoration of the widgets like removing underline in TextFormField widget.
class FormRowWidget extends StatelessWidget {
final Widget inputWidget;
FormRowWidget({this.title, this.inputWidget});
#override
Widget build(BuildContext context) {
var isTextField = inputWidget is TextFormField;
return Container(
padding: EdgeInsets.symmetric(horizontal: 8.0,vertical: 8.0),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.white,
boxShadow: [
new BoxShadow(
color: Colors.black,
blurRadius: 10,
)
],
),
child: inputWidget// I want to change input widgets' properties.
])
}
}
I am using this widget like the code below.
children: <Widget>[
FormRowWidget(
inputWidget: TextFormField(
decoration: InputDecoration(border: InputBorder.none),
controller: usernameController,
validator: (value) {
if (value.length < 4) return "Username err!";
},
onSaved: (value) {
print(value);
},
),
),
FormRowWidget(
inputWidget: TextFormField(
decoration: InputDecoration(border: InputBorder.none),
controller: receiverFirmController,
),
)]
The thing I wonder is what is the best way of overriding inputWidget in my FormRowWidget.
After all, I want to access and change the settings of the widget like the below.Is it possible to handle it?
var customTextWidget = inputWidget as TextFormField;
customTextWidget.decoration

Related

How to make two text fields that show related content, and editable?

I'am trying to do a mobile app which is about crypto currencies.
I want to make two TextFields like USDT and BTC, And they are supposed to work like:
Let me say that BTC is equal to 15$,
And USDT is equal to 1$,
Now those text fields should be editable. so if I write 1 on BTC textfield, USDT textfield should me edited as 15.
Also, when I write 30 on USDT textfield, BTC field should become 2. Moreover, while in this position, if I delete 0 from the usdt field, BTC should updated with "0.something" directly.
How can I do that?
Thanks for the replies !
I managed to do something like USDT is input, and BTC is output. However, I want to make them both input and output. Below are my classes, widgets and codes.
import 'package:cryptx/Constants/app_colors.dart';
import 'package:cryptx/Providers/basic_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class USDTInput extends ConsumerWidget {
const USDTInput({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: TextField(
decoration: InputDecoration(
icon: SizedBox(
height: 30,
child: Image.network(
"https://assets.coingecko.com/coins/images/325/small/Tether.png?1668148663")),
hintText: "USDT",
border: InputBorder.none,
),
onChanged: (value) {
ref
.read(usdProvider.notifier)
.update((state) => value != "" ? num.parse(value) : 0);
},
autocorrect: false,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
),
);
}
}
import 'package:cryptx/Objects/coin.dart';
import 'package:cryptx/Providers/basic_providers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class CoinOutput extends ConsumerWidget {
const CoinOutput({super.key});
#override
Widget build(BuildContext context, WidgetRef ref) {
Coin coin = ref.watch(coinDetailProvider) as Coin;
num usd = ref.watch(usdProvider);
num amount = usd != 0 ? usd / coin.current_price : 0;
//return Text(amount.toString());
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: TextField(
decoration: InputDecoration(
icon: SizedBox(height: 30, child: Image.network(coin.image)),
hintText: "Coin",
border: InputBorder.none,
),
controller:
TextEditingController(text: "$amount ${coin.symbol.toUpperCase()}"),
readOnly: true,
autocorrect: false,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
onChanged: (value) {
ref.watch(coin_usdProvider.notifier).update((state) =>
value != "" ? num.parse(value) / coin.current_price : 0);
},
),
);
}
}
I think the easiest solution would be to create an outside function which can relate/update these two values.
for example:
void updateValues(float BTC, var USDT)
And then use a FocusNode (see also stackoverflow_question) to detect which of the TextFields is/was selected. That was you know which value is the new one and which one to change.
In this solution you should call this function in an onChanged property of the widgets.
FocusNode can be used either to call something when its focus is changed or to check if something has a focus. So using this class you can solve it in a couple different ways.
Try this example out:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final btcTextController = TextEditingController();
final usdtTextController = TextEditingController();
final btcFocusNode = FocusNode();
final usdtFocusNode = FocusNode();
double btcValue = 15;
double usdTValue = 1;
String curSelection = "";
#override
void initState() {
btcTextController.addListener(calcBTC);
usdtTextController.addListener(calcUSDT);
super.initState();
}
void calcBTC() {
if (btcFocusNode.hasFocus) {
usdtTextController.clear();
if (btcTextController.text.isNotEmpty &&
double.tryParse(btcTextController.text) != null) {
setState(() {
usdtTextController.text =
(double.parse(btcTextController.text) * (btcValue / usdTValue))
.toString();
});
}
}
}
void calcUSDT() {
if (usdtFocusNode.hasFocus) {
btcTextController.clear();
if (usdtTextController.text.isNotEmpty &&
double.tryParse(usdtTextController.text) != null) {
setState(() {
btcTextController.text =
(double.parse(usdtTextController.text) * (usdTValue / btcValue))
.toString();
});
}
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Card(
color: Colors.white,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
elevation: 4,
child: Container(
margin: const EdgeInsets.all(10),
width: 300,
height: 300,
child: Column(
children: [
Expanded(
child: TextField(
style: const TextStyle(color: Colors.black),
controller: btcTextController,
focusNode: btcFocusNode,
decoration: InputDecoration(
filled: true,
fillColor: Colors.blue.shade100,
labelText: 'BTC',
labelStyle: const TextStyle(color: Colors.pink),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
)),
),
),
Expanded(
child: TextField(
style: const TextStyle(color: Colors.black),
controller: usdtTextController,
focusNode: usdtFocusNode,
decoration: InputDecoration(
filled: true,
fillColor: Colors.blue.shade100,
labelText: 'USDT',
labelStyle: const TextStyle(color: Colors.pink),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
)),
)),
],
),
),
),
),
),
);
}
}
You will deffo need to add more validation etc. Also you can possibly use one single function to do calculations and use the focusNodes to decide which side needs to be calculated against which.

How can i change TextField on hover in flutter?

Hi i'm trying to change the background color of my TextField Widget in flutter when the user focus on it. But it kinda seems there is no way to do it. If anybody has any idea please let me know ^^.
Here's the Widget itself:
TextField(
controller: emailController,
style: TextStyle(
color: Colors.white, fontSize: 18, height: 0.8),
textAlign: TextAlign.center,
decoration: InputDecoration(
focusColor: AppColors.inputBackgroundDarkFocus,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Color(color)),
),
filled: true,
fillColor: Color(0xff25282C),
hintText: 'Email',
hintStyle:
TextStyle(fontSize: 18, color: Colors.white),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
),
Thks <3
Hover & focus are two different things, so this might not answer your question, but the below can change field color "on focus" (the cursor is in the field).
If you're implementing purely for Flutter web and you want to handle "hover" you could do the below with a MouseRegion wrapper instead of Focus. Info on MouseRegion.
By wrapping a form field in a Focus widget, you can listen/capture focus changes on that field using the onFocusChange constructor argument (of Focus).
It takes a Function(bool).
Here's an example of an onFocusChange handler function:
onFocusChange: (hasFocus) {
if (hasFocus) {
print('Name GAINED focus');
setState(() {
bgColor = Colors.purple.withOpacity(.2);
});
}
else {
print('Name LOST focus');
setState(() {
bgColor = Colors.white;
});
}
},
If you wrap your field in a Container, you can give the Container a color and change that color using a Focus widget described above.
Here's a full page example (stolen from another answer of mine on a similar topic):
import 'package:flutter/material.dart';
class TextFieldFocusPage extends StatefulWidget {
#override
_TextFieldFocusPageState createState() => _TextFieldFocusPageState();
}
class _TextFieldFocusPageState extends State<TextFieldFocusPage> {
Color bgColor = Colors.white;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// ↓ Add this wrapper
Focus(
child: Container(
color: bgColor,
child: TextField(
autofocus: true,
decoration: InputDecoration(
labelText: 'Name'
),
textInputAction: TextInputAction.next,
// ↓ Handle focus change via Software keyboard "next" button
onEditingComplete: () {
print('Name editing complete');
FocusScope.of(context).nextFocus();
},
),
),
canRequestFocus: false,
// ↓ Focus widget handler, change color here
onFocusChange: (hasFocus) {
if (hasFocus) {
print('Name GAINED focus');
setState(() {
bgColor = Colors.purple.withOpacity(.2);
});
}
else {
print('Name LOST focus');
setState(() {
bgColor = Colors.white;
});
}
},
),
TextField(
decoration: InputDecoration(
labelText: 'Password'
),
),
],
),
),
),
);
}
}
I think you can repeat this for each field you need colored.
Hovering can be managed using the hoverColor property of InputDecoration:
Full source code:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Hover TextField Demo',
home: HomePage(),
),
);
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.all(16.0),
alignment: Alignment.center,
child: TextField(
decoration: InputDecoration(
filled: true,
hoverColor: Colors.indigo.shade200,
hintText: 'Email',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
),
),
);
}
}
Almost every style property can be changed by decoration property, which requires an InputDecoration object.
To handle the hover style, this object provides only the hoverColor property, which overwrite the filledColor when the mouse is hovering the widget. The filled property needs to be true for this to work.
InputDecoration(
filled: true,
hoverColor: Colors.red,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
The problem is when you want to change others style properties like the border for example.
In that case you need to make your widget Statefull and add a state boolean like isHover.
Then you could wrap your widget inside MouseRegion and handle the hovering like in this example:
return MouseRegion(
onEnter: (_)=>setState(()=>isHover = true),
onExit: (_)=>setState(()=>isHover = false),
child: YourWidget(),
);
Once isHover is available you can use wherever you want to change the UI according to the hover state.
Example with border:
TextField(
decoration: InputDecoration(
filled: true,
hoverColor: Colors.red,
border: isHover? OutlineInputBorder(
borderSide: BorderSide(
color: Colors.green,
width: 1.5,
),
borderRadius: BorderRadius.circular(8.0),
) : null,
//By leaving null, the component will use the default value
),
),
I think the limitation is due to the fact that the hover behaviour is more web/desktop related. I hope flutter is going to implement better properties to handle this inside InputDecoration.

Flutter - Hide hint text when Text Field have focus

I need to know how to hide the hint text when I focus on the text field. This is my code:
class _ContactoState extends State<Contacto> {
FocusNode focusMsj;
#override
void initState() {
super.initState();
focusMsj = FocusNode();
focusMsj.addListener(() {
if (!focusMsj.hasFocus) {
FocusScope.of(context).requestFocus(focusMsj);
}
});
}
TextField(
focusNode: focusMsj,
hintText: focusMsj.hasFocus ? ' ' : 'Hint Text',)
return WillPopScope(
child: Listener(
onPointerUp: (e) {
focusMsj.hasFocus ? FocusScope.of(context).requestFocus(FocusNode()): '';
},
Thank you
For doing that matter you need to make something like that
class Play extends StatefulWidget {
#override
_PlayState createState() => _PlayState();
}
class _PlayState extends State<Play> {
FocusNode focusNode = FocusNode();
String hintText = 'Hello , iam Hint';
#override
void initState() {
// TODO: implement initState
super.initState();
focusNode.addListener(() {
if (focusNode.hasFocus) {
hintText = '';
} else {
hintText = 'Hello , iam Hint';
}
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
print(focusNode.hasFocus);
}),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
focusNode: focusNode,
decoration: InputDecoration(
hintText: hintText,
),
),
TextField(
decoration: InputDecoration(
hintText: '!!',
),
),
],
),
),
);
}
}
Shortly i listened to TextField by its focusNode property . When TextField has focus i make hintText property equal empty String value
There is a property for that:
TextField(decoration: InputDecoration(hasFloatingPlaceholder: false));
Edit: The version above is deprecated, the new version is:
TextField(decoration: InputDecoration(floatingLabelBehavior: FloatingLabelBehavior.never,),),
One simple solution you can try is define labelText with FloatingBehavior.never
TextField(
decoration: InputDecoration(
labelText: "Search",
floatingLabelBehavior: FloatingLabelBehavior.never,
)
)
HintText will be shown when it is not focussed. On focus, hint text will disappear.
Simply, don't add the hintText in the InputDecoration and mention only the labelText: 'Label' alongside labelStyle if you want to change the style of the label.
TextField(
decoration: InputDecoration(
labelText: "Label",
labelStyle: TextStyle(
color: Colors.blueGrey,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
)
)
My understanding is there is no way to implement it without custom code. Hiding hintText when focused with "border: InputBorder.none," gives perfect login widget example as FloatingLabelBehavior and having animated labelText just won't do. floatingLabelBehavior: FloatingLabelBehavior.never - helps in some situtations but not the exact thing we wanted. If you have labelText and hintText FloatingLabelBehavior.never is helpful to control hiding and showing hintText and animating labelText above the field. WIth custom code we have
String emailHintText = "E-mail";
on the top of state class. Then:
Container(
decoration: BoxDecoration(
border: Border.all(color: white),
borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: EdgeInsets.all(10),
child:
Focus(
onFocusChange: (hasFocus) {
if (hasFocus) {
setState(() {});
emailHintText = "";
}
else {
setState(() {});
emailHintText = "E-mail";
}
},
child: TextFormField(
decoration: InputDecoration(
hintText: emailHintText,
border: InputBorder.none))));
Now, you should know that using setState is a bit costly operation and may not be the best option if not used for very important functionalities.
This works perfectly for me. Just add on InputDecoration ( floatingLabelBehavior: FloatingLabelBehavior.never) of TextField or TextFormField.
TextFormField( controller:_controller, decoration : InputDecoration( label: Text('Entrer your code here '), floatingLabelBehavior: FloatingLabelBehavior.never, ), );

Flutter:Array of Textformfield validator not working

I am working on an Array of Textformfields. The Array can be more than 50. I want to submit array of values to the server. The issue is when I execute validator it will be validating the first 8 in the array after that no error message. That too disappears when scrolling. I posted my code below:
void validateAndSave() {
final form = _formKey.currentState;
if (form.validate()) {
_formKey.currentState.save();
print('Form is valid');
}
else {
// _formKey.currentState.
print('form is invalid');
}
}
Widget singleItemList(int index) {
Item item = itemList[index];
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.white,
),
child:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child:Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 10, 20),
child: new TextFormField(
controller: _controller[index],
keyboardType: TextInputType.number,
//onSubmitted: (text) {
// takeNumber(text, item.id);
//},
validator: (value) {
if (value.isEmpty) return 'value is required';
},
decoration: new InputDecoration(
border: new OutlineInputBorder(
borderSide: new BorderSide(color: Colors.indigo)),
labelText: itemList[index].id,
suffixStyle: const TextStyle(color: Colors.red)
),
),
),
),
],
),
);
}
Please help me. Thanks in advance.
Regards,
Sathish
Have you considered replacing ListView.builder with Column?
Like this:
child: SingleChildScrollView(
child: Column(
children: List.generate(itemList.length, (index) {
if (itemList.isEmpty) {
return CircularProgressIndicator();
} else {
return singleItemList(index);
}
})
)
)
From ListView documentation:
Destruction
When a child is scrolled out of view, the associated element subtree, states and render objects are destroyed. A new child at the same position in the list will be lazily recreated along with new elements, states and render objects when it is scrolled back.

How do I create padding inside a list of text fields?

I am trying to create a registration widget. Most of the work I have done is finished and works.
I only have some issues with padding between my listed textfields.
How do I create a padding?
According to stack overflow this post is mostly code so here is some plain text because I really cannot say more about this, I have aksed my question and provided my code.
var entries = [];
class RegisPage extends StatefulWidget {
#override
_RegisPageState createState() => _RegisPageState();
}
class _RegisPageState extends State<RegisPage> {
#override
Widget build(BuildContext context) {
Map<String,TextEditingController> textEditingControllers = {};
var textFields = <TextFormField>[];
entries.forEach((str) {
var textEditingController = TextEditingController();
textEditingControllers.putIfAbsent(str, ()=>textEditingController);
return textFields.add(
TextFormField(
controller: textEditingController,
decoration:
InputDecoration(
labelText: str,
border:
OutlineInputBorder(
borderRadius:
BorderRadius.circular(25.0)
)
),
),
);
});
return Scaffold(
appBar: AppBar(
title: Text('Registration'),
),
body:Center(
child:
SingleChildScrollView(
child:
Column(
children:[
Column(children:textFields),
RaisedButton(
child: Text("Register"),
onPressed: (){
entries.forEach((str){
print(textEditingControllers[str].text);
});
}
)
]
)
)
)
);
}
}
If you want to add spacing you can just wrap the TextFormField with padding like this:
Padding(
padding: EdgeInsets.fromLTRB(left, top, right, bottom),
child: TextFormField(
controller: textEditingController,
decoration: InputDecoration(
labelText: str,
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(25.0)
)
),
),
),
Then instead of having a list of TextFormField you could do List<Widget>
Like this:
var textFields = <Widget>[];
Everything should still work the same, but now you can specify padding/spacing on all sides.
Hope this helps!