Optional IconData on constructor - flutter

I'm studying Flutter, so I'm just a newbie.
I tried to create a widget with an optional IconData type parameter in the constructor, but I was getting an error.
I got added "?" in front of the local variable. From then on, I just had to enclose the constructor parameters in "{ }". I've found a way to make it work, but I'm not sure it is the best/correct way to do so.
If you have any tip, I'll be happy to hear it!
That's my code:
class Editor extends StatelessWidget {
final TextEditingController controlador;
final String label;
final String hint;
final IconData? fieldIcon;
Editor(
{required this.controlador,
required this.label,
required this.hint,
this.fieldIcon});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(16.0),
child: TextField(
controller: controlador,
style: const TextStyle(
fontSize: 24.0,
),
decoration: InputDecoration(
labelText: label,
hintText: hint,
icon: fieldIcon != null ? Icon(fieldIcon) : null,
),
),
);
}
}

Your code is correct. Nothing inappropriate in my opinion.
However, I feel the following checking for is redundant:
icon: fieldIcon != null ? Icon(fieldIcon) : null,
Given that the icon property of InputDecoration already takes a nullable icon, why not give it just that?
Maybe change the type of fieldIcon from IconData? to Icon? itself. Then, where you consume the icon in the InputDecoration, simply give it the nullable fieldIcon:
icon: fieldIcon,
But wherever you use this Editor widget, remember to give it an Icon for fieldIcon and not an IconData.

Related

How best to convert old Dart code that triggers "parameter can't be 'null' but the implicit default value is 'null'." error?

Take the following non-null safe Dart code:
class RoundedButton extends StatelessWidget {
RoundedButton({this.title, this.color, #required this.onPressed});
final Color color;
final String title;
final Function onPressed;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
elevation: 5.0,
color: color,
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
onPressed: onPressed,
minWidth: 200.0,
height: 42.0,
child: Text(
title,
style: TextStyle(
color: Colors.white,
),
),
),
),
);
}
}
With regards to the constructor's parameters, Android Studio is saying, "The parameter [parameter] can't have a value of 'null' because of its type, but the implicit default value is 'null'."
I understand the error and have discovered that I can simply modify the code like this:
class RoundedButton extends StatelessWidget {
RoundedButton({this.title, this.color, required this.onPressed});
final Color? color;
final String? title;
final Function onPressed;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
elevation: 5.0,
color: color,
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
onPressed: onPressed.call(),
minWidth: 200.0,
height: 42.0,
child: Text(
title!,
style: TextStyle(
color: Colors.white,
),
),
),
),
);
}
}
This way, I satisfy the language rules, but using the bang operator to do the "force unwrap" is presumably frowned upon.
So my solution seems hacky... so in this scenario, what is the elegant, proper, or even sexy way to convert this code to null safety, and if there are multiple ways, then what are the pros and cons?
Thanks!
There are several ways to migrate to null safe code, as you said, making all variables nullable is a possible solution, here are two others:
1. Making the variable have a default value
from:
final String title;
to:
final String title = '';
or
MyClass {
MyClass({this.title=''});
final String title;
}
When to use
If you have a variable that should start with some value and change as time goes on or if you have a variable that is unlikely to be unique to each instance.
GOOD
int timesOpened = 0;
BAD
int uniqueValue = 0 // if it should be unique, it shouldn't be default.
2. Forcing a value at the constructor
from:
MyClass {
MyClass({this.title});
final String title;
}
to:
MyClass {
MyClass({required this.title});
final String title;
}
When to use
When you have a value that must be passed to each instance and that is likely to be different for each instance
GOOD
MyClass({required this.onPressed});
BAD
MyClass({required this.textSize}); // probably should have a default text size value
If I were you, I'd make color have a default value and title and onPressed be required parameters. But You'd know better than me.

How to Change border color of Radio widget in Flutter?

What I Currently Have
What I want to achieve
The Code that I have now
Radio(
value: 2,
groupValue: val,
onChanged: (value) {
setState(() {
val = value;
});
},
activeColor: secondaryColor,)
It's not possible to customize that much the Radio button. The only color parameter for the button is fillColor. It will impact both the inner plain circle and the outer circle.
If you really want a custom look you'll need to build your own widget.
Here is a simple example that you can customize and improve. You could also try to start from the source code of the flutter Radio widget.
class CustomRadio extends StatefulWidget {
final int value;
final int groupValue;
final void Function(int) onChanged;
const CustomRadio({Key? key, required this.value, required this.groupValue, required this.onChanged})
: super(key: key);
#override
_CustomRadioState createState() => _CustomRadioState();
}
class _CustomRadioState extends State<CustomRadio> {
#override
Widget build(BuildContext context) {
bool selected = (widget.value == widget.groupValue);
return InkWell(
onTap: () => widget.onChanged(widget.value),
child: Container(
margin: const EdgeInsets.all(4),
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(shape: BoxShape.circle, color: selected ? Colors.white : Colors.grey[200]),
child: Icon(
Icons.circle,
size: 30,
color: selected ? Colors.deepPurple : Colors.grey[200],
),
),
);
}
}
Result :
There is no way to provide the color of the outer circle in the material Radio class, what you can do is to create your own radio Button, either from scratch (Check the #Tanguy answer)or you copy the Radio class and change its design/behavior.
If you decide to copy the Radio class you need to inherit from the Radio so it can work with the rest of the Material design elements.
Here is a copy of it https://gist.github.com/karimkod/8f7c93da798670c8b6e9b85ff9fb5383
You can change the paint method of The _RadioPainter class to draw basically whatever you want. I have changed it in the gist to look purple.

Flutter TextField value always null on ios device?

I am currently testing my Flutter app on both my iPhone 8 and my Android moto G8.
However, the issue I am running into is that while everything works well on my Android moto G8, on my iPhone it seems that whenever I change a TextField the value in the previous TextField becomes null i.e.:
flutter: This is in error: 'package:firebase_auth/src/firebase_auth.dart': Failed assertion: line 174 pos 12: 'email != null': is not true.
But When I was typing on the device the printout is:
flutter: This is in email:test#gmail.com, value: test#gmail.com
Here is the code for my custom textfield:
class InputTextFields extends StatefulWidget {
InputTextFields({this.title, this.obscureText, this.setValue});
final String title;
final bool obscureText;
Function setValue;
final TextEditingController _controller = TextEditingController();
#override
_InputTextFieldsState createState() => _InputTextFieldsState();
}
class _InputTextFieldsState extends State<InputTextFields> {
#override
Widget build(BuildContext context) {
String hintText;
return Container(
padding: EdgeInsets.only(bottom: 10, left: 35, right: 35),
child: TextField(
obscureText: widget.obscureText,
decoration: InputDecoration(
labelText: widget.title,
labelStyle: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.grey),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
),
),
hintText: hintText,
),
onChanged: widget.setValue,
),
);
}
}
So I am sure the TextField is working as intended but the error still persists. Any ideas how I can solve this?
The problem seems to be from your onChanged: widget.setValue in your TextField. Your function is making the previous TextField null. The best way to retrieve the value of a TextField is to use a TextEditingController. In order to use a TextEditingController in your custom TextField, you would have to pass it as a parameter.
class InputTextFields extends StatefulWidget {
InputTextFields({this.title, this.obscureText, this.controller});
final String title;
final bool obscureText;
final TextEditingController controller;
}
In your TextField:
controller:widget.controller
This is how you use that new custom TextField:
final TextEditingController myController=TextEditingController();
InputTextFields(title:"Test",obscureText:false,controller:myController),
I think you are trying to validate if the TextField's value is an email or not. You could easily check it by using RegExp or by using https://pub.dev/packages/email_validator package. You could also use TextFormField instead of TextField to check if the TextField's value is null. Have a look at this: https://flutter.dev/docs/cookbook/forms/validation. Good Luck!

Flutter: Set default TextField property across the whole app

Is there a way I can set the default TextField textCapitilisation to TextCapitilisation.sentences so that I do not have to add to it every TextField?
Ideally in ThemeData?
Like # F Perroch said, I don't think that is possible too but you can create a Custom TextField for all of your TextField Widgets and use them where appropriate like the exmaple below:
Create a CustomTextField widget like below
class CustomTextField extends StatelessWidget {
/// define property of text fields you want here
final String hinText;
final String labelText;
final Widget icon;
final TextStyle labelStyle;
CustomTextField({this.hinText, this.labelText, this.icon, this.labelStyle});
#override
Widget build(BuildContext context) {
return TextField(
// set your text capitalization here
textCapitalization: TextCapitalization.sentences,
decoration: InputDecoration(
/// set other properties here
hintText: hinText,
labelText: labelText,
labelStyle: labelStyle,
prefixIcon: icon,
),
);
}
}
Call the CustomTextField widget anywhere like below
CustomTextField(
hintText: 'Hello',
labelText: 'Hi there',
labelStyle: TextStyle(....),
icon: Icon(Icons.person)
),
I hope this answers your question.

I am receiving "Invalid constant value" when trying to add a styling theme to title in BottomNavigationBarItem

I am adding a theme to the title in the BottomNavigationBarItem and i am receiving the error "Invalid constant value".
I know it isn't the type of themeing i am using because i was able to break up my theme method and use the individual constants in the next BottomNavigationBarItem. Hmmm i was going to post a picture showing exactly what i mean here but i guess i cant yet.
this is the code that is telling me i have Invalid constant values
BottomNavigationBarItem(
icon: Icon(CustomIcons.wrestlingring2),
title: Text('Event', style: Theme.of(context).textTheme.button),
),
this code is where i added the const values directly to the style from my buttonTheme method in my styling page
BottomNavigationBarItem(
icon: Icon(CustomIcons.wrestling),
title: Text('Match Details', style: TextStyle(fontFamily: montserratFont, fontSize: smallTextSize, color: textColorLight)),
),
this is the constant values and buttonTheme from the styling page
const smallTextSize = 14.0;
const Color buttonTextColour = Color(0xffdc0000);
const String montserratFont = 'Montserrat';
const buttonTextStyle = TextStyle(
fontFamily: montserratFont,
fontSize: buttonTextSize,
color: textColorLight,
);
I noticed in the flutter code the BottomNavigationBarItem is a const and thought this might be the issue
const BottomNavigationBarItem({
#required this.icon,
this.title,
Widget activeIcon,
this.backgroundColor,
}) : activeIcon = activeIcon ?? icon,
assert(icon != null);
but then i noticed so is the RaisedButton but it is not effected by me adding a theme to it.
const RaisedButton({
Key key,
#required VoidCallback onPressed,
ValueChanged<bool> onHighlightChanged,
ButtonTextTheme textTheme,
If there is another way to use theme with the title in the NavigationBarItem i would appreciate it if someone could point it out. I would rather not have to theme the entire ButtomNavigationBar.