How can I copy another buttons style? - dart

I have a TextField widget with the labelText "Description".
I'm trying to make this TextField have the same style as a FlatButton widget
I was reading about using copyWith but I don't fully understand how to use it.
I was also looking at https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/flat_button.dart but I don't really think this explains much
return TextField(
style: TextStyle(),
onChanged: _bloc.changeEventDescription,
decoration: InputDecoration(
labelText: "Description", border: InputBorder.none),
);
Setting border: InputBorder.none at least got rid of the line underneath the FlatButton
The dream is for TextField to look like a default FlatButton
Thanks!!

You can extend FlatButton and create a custom widget (just like FlatButton extends MaterialButton). So your class will look something like this -
class myButton extends FlatButton {}
You can override child to TextFormField.

Related

Flutter default font size

I want to have a default font size to the Text widget in Flutter.
I know that I can set default font family in theme but there is no default font size parameter.
I just wonder if my custom widget is implemented well or I did it wrong approach?
import 'package:flutter/material.dart';
/// Custom Text with a default font Monospace and a default font size.
class CustomText extends Text {
/// Custom Text Constructor extend of Text constructor.
CustomText(this.dataCustom,
{this.styleCustom = const TextStyle(), this.textAlignCustom})
: super(dataCustom,
style: styleCustom.copyWith(fontFamily: 'Monospace', fontSize: 12),
textAlign: textAlignCustom);
/// The text to display.
///
/// This will be null if a [textSpan] is provided instead.
final String dataCustom;
/// If non-null, the style to use for this text.
///
/// If the style's "inherit" property is true, the style will be merged with
/// the closest enclosing [DefaultTextStyle]. Otherwise, the style will
/// replace the closest enclosing [DefaultTextStyle].
final TextStyle styleCustom;
/// How the text should be aligned horizontally.
final TextAlign textAlignCustom;
}
Thanks
A Flutter theme defines not one, but many default font sizes. The size used depends on the situation, e.g. a Text widget would normally use body style, but the same widget would use button style if used inside of a button.
I found two ways to increase all font sizes across a Flutter application.
Simple solution: adjust the default theme
MaterialApp(
theme: ThemeData(
textTheme: Theme.of(context).textTheme.apply(
fontSizeFactor: 1.1,
fontSizeDelta: 2.0,
),
),
...
);
The resulting font size is (originalSize * fontSizeFactor + fontSizeDelta). So in the example above all font sizes are increased by 10% and then additionally by 2.
Solution with more control: define all sizes by hand
MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
bodyText1: TextStyle(fontSize: 18.0),
bodyText2: TextStyle(fontSize: 16.0),
button: TextStyle(fontSize: 16.0),
... // and so on for every text style
),
),
...
);
The full list of styles can be found at https://api.flutter.dev/flutter/material/TextTheme-class.html.
I found a better way for default font size by overriding the material text theme.
Reference: https://api.flutter.dev/flutter/material/TextTheme-class.html
For example:
body1 is for normal Text widgets
so for the red color to all Text widgets
theme: ThemeData(
textTheme: TextTheme(body1: TextStyle(backgroundColor: Colors.red))
)
Result:
You should prefer composition over inheritance.
class Mono12Text extends StatelessWidget {
final String data;
final TextAlign align;
final TextStyle style;
Mono12Text(
this.data, {
this.align,
TextStyle style = const TextStyle(),
}) : style = style.copyWith(
fontFamily: 'Monospace',
fontSize: 12,
);
#override
Widget build(BuildContext context) {
return Text(
data,
textAlign: align,
style: style,
);
}
}
Expanding a bit on amorenew's answer.
You can set the fontSize inside the the MaterialApp() Widget. However note that it will not work inside all widgets, for example Flatbutton and ExpansionTile.
void main() {
runApp(myApp());
}
class myApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "My Flutter App",
theme: ThemeData(
textTheme: TextTheme(body1: TextStyle(fontSize: 20.0)),
...
);
}
}
So if you want the style to be applied also to a FlatButton:
FlatButton(
child:
Text("my text",
style: Theme.of(context).textTheme.body1,
)
);
And, if you want the fontSize to be applied with other specific styles:
FlatButton(
child:
Text("my text",
style:
TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: Theme.of(context).textTheme.body1.fontSize
)
)
);
There are several possibilities:
1- Using the DefaultTextStyle widget :
Just use this widget as a parent
Example :
DefaultTextStyle(
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
child: Text('Hello World') // I don't need to define a style for this Text widget anymore
),
Output :
I don't need to define a style for this Text widget anymore because it
will default to the DefaultTextStyle widget style.
See also:
AnimatedDefaultTextStyle, which animates changes in the text style smoothly over a given duration.
DefaultTextStyleTransition, which takes a provided Animation to animate changes in text style smoothly over time.
2- The use of the predefined textTheme :
In fact, all you have to do is choose a predefined textTheme and use or modify it :
Each textTheme has a predefined TextStyle that you can use directly or modify before using it.
Here is the list of the predefined textTheme :
headline1, headline2, headline3, headline4, headline5, headline6, subtitle1, subtitle2, bodyText1, bodyText2, caption, button, overline, display4, display3, display2, display1, headline, title, subhead, subtitle, body2, body1
Usage:
Text('Hello World' , style: Theme.of(context).textTheme.headline6,),
Output :
You can also change the value of this TextStyle and then reuse it.
Modification :
Put it in your MaterialApp widget .
theme: ThemeData(
textTheme: TextTheme(
headline6: TextStyle(fontSize: 15 , color: Colors.blue),
bodyText1: TextStyle(backgroundColor: Colors.red , color: Colors.blue) ,
)
),
Output :
My code is here
Learn more about TextTheme here .
You should use DefaultTextStyle widget as a parent widget
The text style to apply to descendant Text widgets which don't have an explicit style
Example on how to use:
return DefaultTextStyle(
style: TextStyle(fontSize: 42, color: Colors.blue),
child: (...)
);
More details in official documentation
fontSize:styleCustom.fontSize!=null ? styleCustom.fontSize:10),## you did right except situations which you have default value like font size but you want override it ##

How to display text in 'Text' widget after flatButton press?

I'm trying to make a calculator app using flutter where instead of taking input through the keyboard I want to take input through some buttons. The issue comes when I press a button but it does not display the corresponding data in the Text widget above.
All my classes are stateless except for the first MyApp class, which is Stateful.
I tried by creating a general variable outside all the classes and using that to transfer text from the button class to the display class but that did not work.
The general variable is "_calcText"
class DisplayAnswer extends StatelessWidget {
final String _text;
DisplayAnswer(this._text);
#override
Widget build(BuildContext context) {
return Expanded(
flex: 2,
child: Material(
color: Colors.greenAccent,
child: Ink(
padding: EdgeInsets.all(10.0),
child: Center(
child: Container(
constraints: BoxConstraints.expand(),
decoration: BoxDecoration(border: Border.all(color: Colors.black, width: 5.0), color: Colors.white),
child: Text(_text,style: TextStyle(fontSize: 50.0), textAlign: TextAlign.center,),
),
),
),
),
);
}
}
class NumButtons extends StatelessWidget {
final String _number;
NumButtons(this._number);
#override
Widget build(BuildContext context) {
return FlatButton(
onPressed: () {
_calcText = _calcText + _number;
print(_calcText);
DisplayAnswer(_calcText);
} ,
child: Text(_number.toString(), style: TextStyle(fontSize: 30.0),),
color: Colors.white
);
}
}
I want to display the value of _calcText in the Text widget of DisplayAnswer. I want _calcText to also change as other buttons are clicked, ie; if 2 is clicked Text should only display 2, if 5 is clicked after that it should display 25
The full code is here:
https://drive.google.com/open?id=1C4MLAkjowloicbjBP_uV8BfpPzhz4Yxf
Use Statefull widget insted of StatelessWidget.
Call the setState() method on onPressed function, after adition operation. It will build your widget with a new value.
On DisplayAnswer, you have to make a function to increment the value, than pass this function as parameter to NumButtons.
Pass a callback Function to NumButtons, like:
class NumButtons extends StatelessWidget {
final String _number;
final Function callback;
...

How to prevent keyboard from dismissing on pressing submit key in flutter?

I'm making a flutter application where user can type a message and hit send button IN THE KEYBOARD to send the message. The problem is when I press the send button the message gets send but the keyboard gets automatically dismissed. How can I prevent that from happening?
Thanks in advance.
TextField(
autofocus: true,
keyboardType: TextInputType.multiline,
maxLines: null,
decoration: new InputDecoration.collapsed(
hintText: "Let's talk",
border: UnderlineInputBorder(
borderRadius: BorderRadius.circular(1),
),
),
textInputAction: TextInputAction.send,
onSubmitted: null,
)
TextField widget has a parameter just for this purpose!
While onSubmit callback can be used to handle business logic when the user presses done, there is also a property called onEditingComplete, specially made to handle focus-related logic. So you should use both, for better code readability.
According to the docs:
The default implementation of onEditingComplete executes 2 different
behaviors based on the situation:
When a completion action is pressed, such as "done", "go", "send", or
"search", the user's content is submitted to the controller and then
focus is given up.
When a non-completion action is pressed, such as "next" or "previous",
the user's content is submitted to the controller, but focus is not
given up because developers may want to immediately move focus to
another input widget within onSubmitted.
Therefore, if you don't like this behaviour, for example, "send" is considered a "completion action" here, thus in an Instant Messaging (chatting) app, each time user sends a short message, the keyboard will be collapsed. But if we override the onEditingComplete callback to an empty function, it will stop the default behavior and not hide the keyboard.
Sample code:
TextField(
controller: _controller,
onSubmitted: (value) {
sendMessage(text);
_controller.clear();
},
onEditingComplete: () {}, // this prevents keyboard from closing
textInputAction: TextInputAction.send,
)
Demo:
For complete explanation and comparison between onSubmitted and onEditingComplete callbacks, check out my other answer here.
This worked for me:-
First Create a FocusNode and assign it to your textfield, do the following :-
The FocusNode is a long lived component so initialize it in the initState method:-
FocusNode inputFieldNode;
#override
void initState() {
super.initState();
inputFieldNode = FocusNode();
}
Do not forget to cleanup the FocusNode in dispose method after the Form is disposed:-
#override
void dispose() {
inputFieldNode.dispose();
super.dispose();
}
Assign the FocusNode to the textfield and write the following code in onSubmitted::-
TextField(
focusNode: inputFieldNode,
onSubmitted: (String) => FocusScope.of(context).requestFocus(inputFieldNode),
)
Now the textfield will not lose focus even after pressing the submit button.
The cleanest approach would be to use onEditingComplete() with TextEditingController instead of onSubmitted(text). Refer below example.
final _controller = TextEditingController();
TextField(
controller: _controller,
padding: EdgeInsets.all(8),
textInputAction: TextInputAction.send,
placeholder: 'Type your message',
onEditingComplete: (){
if (_controller.text.isEmpty) return;
sendMessage(_controller.text);
},
),
// Focus node
FocusNode _myTextFieldFocusNode = FocusNode();
Widget build(BuildContext context) {
return SafeArea(
body: Focus(
onFocusChange: (hasFocus) => !hasFocus ? _myTextFieldFocusNode.requestFocus() : null
Container(
child: // child goes here
)
),
);
}
If the user taps to something like it can "dismiss the keyboard" Focus() widget will detect
changes and this is where you might want to put your _myTextFieldFocusNode.requestFocus()
keyboard won't have a chance to dismiss and reopen again
SystemChannels.textInput.invokeMethod('TextInput.show');
on onSubmit method

How can I get rid of the animation on the InkWell widget?

I have a problem. I have an InkWell widget but I don't want it to have that splash screen animation. Is there a way to get rid of this animation?
If you don't care about the splash animation, do not use InkWell. That widget exists only for that.
Instead use GestureDetector, which is basically an InkWell without the animation.
If you do not want any feedback you could add splashColor: Colors.transparent and highlightColor: Colors.transparent
InkWell Widget has a SplashColor property
class Whatever extends StatelessWidget {
#override
Widget build(BuildContext context) {
// The InkWell Wraps our custom flat button Widget
return InkWell(
// When the user taps the button, show a snackbar
onTap: () { /*or your custom implementation*/
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Tap'),
));
},
splashColor: Colors.transparent, /*This is what you need to include*/
child: Container(
padding: EdgeInsets.all(12.0),
child: Text('Flat Button'),
),
);
}
}

StreamBuilder child widget interaction

The following code builds and runs as intended--when a user types something, an error message gets shown until the string passes an email validation format.
Widget emailField(){
return StreamBuilder(
stream: bloc.emailStream,
builder: (BuildContext context, snapshot) {
return TextField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'you#example.com',
labelText: 'E-mail address',
errorText: snapshot.error
),
onChanged: (newValue){
bloc.updateEmail(newValue);
},
);
},
);
}
I am told that when the stream changes, the builder field gets called which rebuilds the TextField. But if that is the case, shouldn't the TextField always have a blank string? What happens instead is it retains its value.
I am trying to understand what exactly is happening here. Thanks!
Not really, If you look at the code of the TextField , you'll find it's a StatefulWidget, so its has a State and the state keep the value.
class TextField extends StatefulWidget
Additionally you can use the TextEditingController to handle(get/clear/set) the data of the TextField , if you don't provide a TextEditingController it will be created by default as you can see in the source code.
#override
void initState() {
super.initState();
if (widget.controller == null)
_controller = TextEditingController();
}
You can find more information here: https://flutter.io/cookbook/forms/text-field-changes/
TextField widget is newly created, but it's corresponding element is reused/recyled (and so is it state).
Here's a pretty good explanation from the creator: https://youtu.be/AqCMFXEmf3w?t=99

Resources