Flutter manage all the extra arguments - flutter

In my flutter code, I have created a widget called BeautifulTextField. I use a similar design for all my text fields in my code, so I just copied it into one class. However, a text field can have many parameters, such as enableSuggestions, autocorrect, focusNode etc. Only 1 out of 10 text fields might require these parameters. How can I manage them? This is my current code.
String placeholder="";
IconData icon;
bool passField;
double fontSize;
EdgeInsets paddingText;
BeautifulTextField(this.placeholder,this.icon,[
this.passField=false,
this.fontSize = -1,
this.paddingText = const EdgeInsets.fromLTRB(10,10,20,10)
]);
To elaborate further, I achieved this in react like this:
const Inputs = (props) => {
return <input {...props} className="textfield"/>
}
Is there a similar feature in Flutter?

Why don‘t you inherit a base class to a detailed class
class BeautifulText {
base properties
}
class MostBeautifulText extends BeautifulText {
extra properties
}

You can use those fields as below when that fields are Optional,
String placeholder = "";
IconData icon;
bool passField;
double fontSize;
EdgeInsets paddingText;
bool enableSuggession;
bool autoCorrect;
FocusNode focusNode;
BeautifulTextField(this.placeholder, this.icon, this.passField, this.fontSize, this.paddingText,
{this.enableSuggession, this.autoCorrect, this.focusNode});

Related

how to create a constructor in flutter with null safety

This got a bit tricky for me. since we can no longer pass null values in contructor I had this
class LeadingButton extends StatelessWidget {
final IconData icon;
final Color color;
final Color iconColor;
final double iconSize;
final double size;
final Color backGroundColor;
final VoidCallback onPressed;
final double padding;
final EdgeInsets margin;
final double rotate;
LeadingButton({
#required this.icon,
this.color = Colors.transparent,
#required this.onPressed,
this.size = 20,
this.backGroundColor = Colors.transparent,
this.iconSize = 20,
this.iconColor = darkColor,
this.rotate = 0,
this.padding = 0,
this.margin = const EdgeInsets.all(10)});
...
I am getting an error on icon and onpressed function. although the
documentation is saying
The parameter 'onPressed' & 'icon' can't have a value
of 'null' because of its type, but the implicit default value is
'null'. Try adding either an explicit non-'null' default value or the
'required' modifier.
I guess I am missing some thing, kindly mind to share
Not sure, but it could be that this is due to the recent change of the keyword.
Did you try the required keyword instead?
https://dart.dev/null-safety/faq#how-does-required-compare-to-the-new-required-keyword
I think that LeadingButton's onPressed type needs to be changed to VoidCallback? so it can accept null values.

Flutter: add a simple wrapper to the Text widget

I came from a React world and trying to get my head around Flutter and Dart.
I'm using the Text widget with the same parameters a lot, so it seems reasonable to think of a way to reuse code. I created a wrapper that uses it:
import 'package:flutter/material.dart';
TextStyle getThemeProperty(type, TextTheme textTheme) {
switch (type) {
case 'headline1':
return textTheme.headline1;
case 'headline2':
return textTheme.headline2;
case 'headline3':
return textTheme.headline3;
default:
return textTheme.bodyText2;
}
}
class CustomText extends StatelessWidget {
const CustomText({Key key, this.type, this.text, this.color}) : super(key: key);
final type;
final text;
final color;
#override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
var style = getThemeProperty(type, textTheme);
if (this.color != null) style.color = this.color;
return Text(
this.text,
style: style,
);
}
}
// Usage
CustomText(
text: 'Some Heading',
type: 'headline2',
color: Colors.black
)
The idea is to set the color if the color property is passed as a parameter, but Dart's compiler doesn't like it. It throws me the error: ''color' can't be used as a setter because it's final.
Try finding a different setter, or making 'color' non-final.'
I'm planning to do the same to fontWeight and textAlign properties as well. How am I able to make this work, I mean, to add new props to the style object on demand?
The reason why the dart compiler is unhappy is just because the color property of the TextStyle is declared as final. Therefore to use a new color, you have to create a new instance of the TextStyle.
Luckily, the TextStyle class comes with a copyWith method that returns an edited copy of your TextStyle
final type;
final text;
final color;
#override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
var style = getThemeProperty(type, textTheme);
return Text(
this.text,
// Added this...
style: style.copyWith(color: color ?? style.color),
);
}
As a side note, when making reusable widgets, it's always a good idea to type your parameters. This is because any type of variable can be used. So instead of passing a String for text, you may pass an int
// DON'T DO THIS
final type;
final text;
final color;
// DO THIS
final String type;
final String text;
final Color color;
Also adding the this keyword to reference a variable in a class without variable shadowing is unnecessary.
// DON'T
this.text
// DO
text

Is there any best practice of how to define the widget's properties visibility in Flutter?

In Java, according to the recommendations of Effective Java (Item 15 ["Minimize Mutability"] in the Second Edition and Item 13 ["Favor Immutability"] in the First Edition):
Fields are final and private.
If a field does not intend to be used externally, it's likely to set it to private, e.g.,
class CustomAppBar extends View {
public CustomAppBar(Context context, String title, Boolean centerTitle) {
super(context);
this.title = title;
this.centerTitle = centerTitle;
}
private final String title;
private final Boolean centerTitle;
}
But in Flutter framework, almost all Flutter widgets use properties as public property, like what I see in AppBar:
class AppBar extends StatefulWidget implements PreferredSizeWidget {
AppBar({
this.title,
this.centerTitle,
...
}): ...
final Widget title;
final bool centerTitle;
...
}
But based on the experience I learned from Java, I should make it more reasonable to change the properties to private, such like:
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
CustomAppBar({
Widget title,
bool centerTitle,
}): _title = title,
_centerTitle = centerTitle;
final Widget _title;
final bool _centerTitle;
...
}
So I am curious, is there any best practice(effective) guide of the visibility of the properties of Flutter widgets?
From Dart Documentation
Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore _, it’s private to its Class, so it is different than Java
So as per you code only:
// these are private entities inside your Class/Activity
final Widget _title;
final bool _centerTitle;

How to pre-define propeties in classes Flutter

I have created a CardText as a stateless widget and I will use it whenever I would be needing it. But I have a problem. As y'all can see, there are properties that I haven't marked as #required. What I want is these properties have a pre-defined value. Like, suppose the color property, it should be 0xFFFFFFFF until and unless I want somewhere to be as 0xFF000000. But these are final properties that can't be assigned on the basis of ??= method. Yes, I know, marking these properties as #required will require me to define each and every property whenever I call it. But having a pre-defined value will help me a lot to save time and a few lines of code.
Well, any expert out there, I don't know how to express the problem, so feel free to change the title. Thank you.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class CardText extends StatelessWidget {
final String data;
final int color;
final int fontSize;
final FontWeight fontWeight;
const CardText(
this.data, {
this.color,
this.fontSize,
this.fontWeight,
});
#override
Widget build(BuildContext context) {
return Text(
data,
style: GoogleFonts.openSans(
textStyle: TextStyle(
fontSize: fontSize,
fontWeight: fontWeight,
color: Color(color),
),
),
);
}
}
If your arguments are optional then you can give default it right away, like following
const CardText({
this.data,
this.color = 0xFFFFFFFF,
this.fontSize = 14,
this.fontWeight,
})
You can use the : colon syntax:
const CardText(
this.data, {
this.color,
this.fontSize,
this.fontWeight,
}) : color = 0xFFFFFFFF, data = "data"
The code after the colon will be executed before the code inside the curly brackets. From the linked question
The part after : is called "initializer list. It is a ,-separated list
of expressions that can access constructor parameters and can assign
to instance fields, even final instance fields. This is handy to
initialize final fields with calculated values.

Flutter Gallery demo: Cards to change card's height

I am trying to modify the cards_demo.dart found in Flutter examples. My purpose is that instead of having the built-in two cards' height be fixed as:
static final double height=300.0 (or some mandatory and fixed number), I want to have different height for the two cards.
So I modified the TravelDestination class to include a property height:
class TravelDestination {
const TravelDestination({ this.assetName, this.title, this.description, this.height });
final String assetName;
final String title;
final List<String> description;
final double height;
bool get isValid => assetName != null && title != null && description?.length == 3;
}
Then, in class TravelDestinationItem build function:
class TravelDestinationItem extends StatelessWidget {
TravelDestinationItem({ Key key, #required this.destination }) : super(key: key) {
assert(destination != null && destination.isValid);
}
static final double height = 512.0;
final TravelDestination destination;
#override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
final TextStyle titleStyle = theme.textTheme.headline.copyWith(color: Colors.white);
final TextStyle descriptionStyle = theme.textTheme.subhead;
return new Container(
padding: const EdgeInsets.all(8.0),
height: destination.height,
//height: height,
child: new Card(
child: new Column(... ...
I assigned different height property to the two cards but the result is not working: they are still the same height as specified by static final double height.
If I comment out static final double height line, the compiler will remind me: No static getter 'height' declared...
I am very much confused on this behavior.
Can anyone help?
Since you're using items of varying height, you should remove this line from the call to the ListView constructor:
itemExtent: TravelDestinationItem.height,
Also, you'll need to hot-restart the app (hot-reloading won't update the destinations list with the new data, since it's a global variable).