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 ##
Related
My app was built using a MaterialApp as the root widget. To this material app, I've added a theme as follows:
MaterialApp(
theme: myTheme,
home: MyHomePage(),
...
)
final ThemeData myTheme = _buildTheme();
ThemeData _buildTheme() {
final ThemeData base = ThemeData.light();
return base.copyWith(
...
textTheme: _buildMyTextTheme(base.textTheme),
primaryTextTheme: _buildMyTextTheme(base.primaryTextTheme),
accentTextTheme: _buildMyTextTheme(base.accentTextTheme),
pageTransitionsTheme: PageTransitionsTheme(builders: {
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
}));
}
TextTheme _buildMyTextTheme(TextTheme base) {
return base
.copyWith(
headline:
base.headline.copyWith(fontSize: 20.0, fontWeight: FontWeight.w500),
title: base.title.copyWith(fontSize: 18.0, fontWeight: FontWeight.w400),
subhead:
base.subhead.copyWith(fontSize: 16.0, fontWeight: FontWeight.w400),
body1: base.body1.copyWith(fontSize: 14.0, fontWeight: FontWeight.w400),
body2: base.body2.copyWith(fontSize: 14.0, fontWeight: FontWeight.w500),
caption: base.caption.copyWith(
fontWeight: FontWeight.w400,
fontSize: 12.0,
),
)
.apply(
fontFamily: 'myfont',
displayColor: Colors.black,
bodyColor: Colors.black,
);
}
I've used Theme.of(context.textTheme to style the text in the whole app down the widget tree.
for example :
to a title I used
Text('Title', style:Theme.of(context).textTheme.title),
to a subtitle I used
Text('Title', style:Theme.of(context).textTheme.subhead),
It works as intended.
But now I want to use a CupertinoApp if the current platform is ios as it provides with native ios feel like
List item
Pages will be dismissible via a back swipe.
Scrolling past extremities will trigger iOS-style spring overscrolls.
How shall I add the CupertionApp applying the same text theming?
you can wrap the CupertinoApp with Theme widget:
Theme(
data: yourThemeData(), //your theme data here
child: CupertinoApp(...),
);
I am creating a Flutter application which uses the Cupertino widgets. Now I am using the CupertinoSliverNavigationBar, but I did like the title to be multiline.
Currently I have written the following:
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(child: CustomScrollView(slivers: <Widget>[
CupertinoSliverNavigationBar(largeTitle: Text(
"Why doesn't this text wrap? I want it to be multiline...")),
SliverFillRemaining(child: Container())
]));
}
I tried several ways, like putting the Text in a Flexbile but this is not working. Any idea in how I can achieve the desired effect?
The height of the largeTitle is limited and I have found anything to make it bigger, so the solution that I propose require to make the text smaller.
largeTitle: RichText(
text: TextSpan(children: [
TextSpan(
text: "Why doesn't this text wrap?",
style: TextStyle(color: Colors.black, fontSize: 20)),
TextSpan(text: "\n"),
TextSpan(
text: "I want it to be multiline...",
style: TextStyle(color: Colors.orange, fontSize: 20))
]),
),
I think you should avoid using multiline largeTitle but in case you really want it you can try this.
When the user scrolls to the edge of a list or TabView, an animated blue circle appears on the ending edge.
What is this called, and how do I change the colour of it?
This is the android scroll physics (ClampingScrollPhysics).
From the source code and docs:
glow color is specified to use [ThemeData.accentColor].
That been said, when you create your App, the best practice is to specify a custom theme, istead of appling colors manually.
Example:
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
theme: ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.grey,
primaryColor: Colors.grey[50],
primaryColorBrightness: Brightness.light,
//this is what you want
accentColor: Colors.orangeAccent[400],
accentColorBrightness: Brightness.light,
),
home: Home(),
);
}
}
I like to use this tool to define the primary and secondary (called accent color in flutter) and having a preview of the widgets.
Note: On IOs the physics is different, letting the user scroll beyond the bounds of the content, but then bounce the content back to the edge of those bounds (BouncingScrollPhysics).
Since Flutter v2.3.0-0.1.pre, themes changed
https://api.flutter.dev/flutter/material/ThemeData/accentColor.html
For setting the accent color, you must do something like
class Themes {
static final light = ThemeData(
// Colors
backgroundColor: Colors.white,
primaryColor: MyColors.blue,
splashColor: MyColors.blue,
cardColor: MyColors.blue,
hoverColor: MyColors.blue,
highlightColor: MyColors.blue,
colorScheme: ColorScheme.light(primary: MyColors.blue),
// Fonts
fontFamily: 'Inter');
static final lightV2 = light.copyWith(
colorScheme: light.colorScheme.copyWith(secondary: MyColors.blue));
}
And assign ligthV2 in your MaterialApp
MaterialApp(
...
theme: Themes.lightV2
...
)
I have some texts that contain emojis and I'm trying to show them on the Text widget. However, they seem to be shown as foreign characters. Does Flutter support showing emojis? should work for both iOS and Android
The Problem
As of now, unfortunately, Flutter uses the default Emojis supported on a given platform. Therefore, when building a cross-platform app you may face issues of Emojis showing on certain devices and not on others.
The Solution
The solution I settled for is to use a custom Emoji font such as Emoji One and RichText widget instead of the basic Text widget.
With this, you can simply have:
RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: 'Hello', // non-emoji characters
),
TextSpan(
text: '🧭 🏳️\u200d🌈', // emoji characters
style: TextStyle(
fontFamily: 'EmojiOne',
),
),
],
),
);
Generalized Solution
With this idea, we can even create a custom widget that given a string, builds a RichText object with all the TextSpans autocreated:
class EmojiText extends StatelessWidget {
const EmojiText({
Key key,
#required this.text,
}) : assert(text != null),
super(key: key);
final String text;
#override
Widget build(BuildContext context) {
return RichText(
text: _buildText(this.text),
);
}
TextSpan _buildText(String text) {
final children = <TextSpan>[];
final runes = text.runes;
for (int i = 0; i < runes.length; /* empty */ ) {
int current = runes.elementAt(i);
// we assume that everything that is not
// in Extended-ASCII set is an emoji...
final isEmoji = current > 255;
final shouldBreak = isEmoji
? (x) => x <= 255
: (x) => x > 255;
final chunk = <int>[];
while (! shouldBreak(current)) {
chunk.add(current);
if (++i >= runes.length) break;
current = runes.elementAt(i);
}
children.add(
TextSpan(
text: String.fromCharCodes(chunk),
style: TextStyle(
fontFamily: isEmoji ? 'EmojiOne' : null,
),
),
);
}
return TextSpan(children: children);
}
}
Which can be used as:
EmojiText(text: 'Hello there: 🧭 🏳️\u200d🌈');
This has the advantage of having the consistent support of Emojis on your app that you can control on different platforms.
The downside is that it will add some MBs to your app.
You can insert emoji in the text field through following way:
If you're on Mac, you can hit Control + Command + Space. Windows users can hit the "Windows key" + ; (semicolon).
Copy pasted the instruction from #Reso Coder
https://www.youtube.com/watch?v=KfuUkq2cLZU&t=15s
I tested on mac and it works.
Flutter supports emoji. Here's some code that demonstrates emoji text entry. (If you're seeing foreign characters, it's likely that you're decoding bytes as ASCII instead of UTF-8; we can show you how to fix this if you update your question with code that demonstrates the problem.)
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _message = '🐣';
Future<String> _promptForString(String label, { String hintText }) {
final TextEditingController controller = new TextEditingController();
return showDialog(
context: context,
child: new AlertDialog(
title: new Text(label),
content: new TextFormField(
controller: controller,
decoration: new InputDecoration(hintText: hintText),
),
actions: <Widget>[
new FlatButton(
onPressed: () => Navigator.pop(context),
child: const Text('CANCEL'),
),
new FlatButton(
onPressed: () => Navigator.pop(context, controller.text),
child: const Text('OK'),
),
],
),
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(_message),
),
body: new Center(
child: new Text(_message, style: Theme.of(context).textTheme.display2),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.edit),
onPressed: () async {
String message = await _promptForString('New text', hintText: 'Try emoji!');
if (!mounted)
return;
setState(() {
_message = message;
});
},
),
);
}
}
If you just want to include emoji in Text widget, you can copy emoji from somewhere else and paste it inside the text widget.
I use GeteMoji to copy emojis.
See the Output Screenshot
CODE : See 8th Row.
Widget build(BuildContext context) {
return Center(
child: Container(
alignment: Alignment.center,
color: Colors.deepPurple,
//width: 200.0,
//height: 100.0,
child: Text("Emoji 🤣 ",
style: TextStyle(
fontFamily: 'Raleway',
fontSize: 40,
decoration: TextDecoration.none,
color: Colors.white
))));
}
For full emoji compatibility (at least in android, not all emojis are supported in old OS versions) you can use the google free font Noto Color Emoji at https://www.google.com/get/noto/#emoji-zsye-color
Add it to the fonts folder
add in pubspec.yaml
fonts:
- family: NotoEmoji
fonts:
- asset: fonts/NotoColorEmoji.ttf
weight: 400
use with TextStyle
Text("🤑", TextStyle(fontFamily: 'NotoEmoji'))
When an emoji is not showing up, the issue is most likely the font you are using.
Before trying out an emoji font package, you can give the text field an empty string as fontFamily or try out the default font options packaged with flutter.
This will prevent adding dependencies that are not needed.
for example this emoji was not showing on android with 'Product Sans' as fontFamily, i simply added an empty string and font family for the text field, and that fixed the issue.
Text('₦', TextStyle(fontFamily: ''))
You can easily use the fontFamily as a style to solve the problem
I used it with the package
auto_size_text: ^2.1.0
AutoSizeText(
lesson.FullExercise,
textAlign: TextAlign.justify,
style:TextStyle(
fontFamily: 'EmojiOne',
),
),
Good note to mention
If you want to store data in MySQL and the text contains Emojis you need to change the collection of the text to utf8mb4
How can I have a line of text with different formatting?
e.g.:
Hello World
You should use the RichText widget.
A RichText widget will take in a TextSpan widget that can also have a list of children TextSpans.
Each TextSpan widget can have a different TextStyle.
Here is the example code to render:
Hello World
var text = RichText(
text: TextSpan(
// Note: Styles for TextSpans must be explicitly defined.
// Child text spans will inherit styles from parent
style: const TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
TextSpan(text: 'Hello'),
TextSpan(text: 'World', style: const TextStyle(fontWeight: FontWeight.bold)),
],
),
);
[UPDATE]
The below answer fits best for couple of words and not for a paragraph,If you have a long sentence or a paragraph where you need to format a particular text prefer using RichText as suggested by #DvdWasibi in the above answer
[OLD ANSWER]
I like keeping my code short and clean this is How I Would do it add two text fields in a row one with Normal font and another bold,
Note: This may not look good for a long paragraph looks good for Headlines etc.
Row(children: [
Text("Hello"),
Text("World", style: const TextStyle(fontWeight: FontWeight.bold))
]);
and you should get a desired output as "Hello World"
return RichText(
text: TextSpan(
text: 'Can you ',
style: TextStyle(color: Colors.black),
children: <TextSpan>[
TextSpan(
text: 'find the',
style: TextStyle(
color: Colors.green,
decoration: TextDecoration.underline,
decorationStyle: TextDecorationStyle.wavy,
),
recognizer: _longPressRecognizer,
),
TextSpan(text: 'secret?'),
],
),
);
You should use the Text.rich constructor from Text class here.
By using the rich constructor you can display a paragraph with differently styled TextSpans.
Why I recommended it instead of RichText is because of by using RichText you will required to define the parent TextStyle in RichText but using the rich constructor of Text you don't need explicitly defined the parent TextStyle in Text.rich
Here is the example how to use it with same result
Using RichText
const text = RichText(
text: TextSpan(
// Here is the explicit parent TextStyle
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
fontFamily: 'Montserrat',
),
children: <TextSpan>[
new TextSpan(text: 'Hello'),
new TextSpan(text: 'World', style: new TextStyle(fontWeight: FontWeight.bold)),
],
),
);
Using rich constructor of Text
const text = Text.rich(
TextSpan(
// with no TextStyle it will have default text style
text: 'Hello',
children: <TextSpan>[
TextSpan(text: 'World', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
)
I've solved a similar problem by using flutter_html widget with custom styles for different tags.
Actually, I've got the strings in different languages and some parts of them should be bold, so it wasn't easy to determine which part of the string I should make bold since strings was in l10n locale files. Here is example:
Container(
child: Html(
data: "<p>My normal text <b>with bold part</b> in any place</p>",
style: {
"p": Style(
fontSize: FontSize.large,
fontWeight: FontWeight.normal),
"b": Style(
fontWeight: FontWeight.bold,
),
)
);
I think this approach is useful in case you have a lot of differently styled text inside your regular text.
Regex
You can use this widget. The example below always make numbers bold.
import 'package:flutter/material.dart';
class TextBold extends StatelessWidget{
final String text;
final String regex;
static const _separator = " ";
const TextBold({Key key, this.text, this.regex = r'\d+'}) : super(key: key);
#override
Widget build(BuildContext context) {
final parts = splitJoin();
return Text.rich(TextSpan(
children: parts.map((e) => TextSpan(
text: e.text,
style: (e.isBold)
? const TextStyle(fontFamily: 'bold')
: const TextStyle(fontFamily: 'light')))
.toList()));
}
// Splits text using separator, tag ones to be bold using regex
// and rejoin equal parts back when possible
List<TextPart> splitJoin(){
assert(text!=null);
final tmp = <TextPart>[];
final parts = text.split(_separator);
// Bold it
for (final p in parts){
tmp.add(TextPart(p + _separator,p.contains(RegExp(regex))));
}
final result = <TextPart>[tmp[0]];
// Fold it
if (tmp.length>1) {
int resultIdx = 0;
for (int i = 1; i < tmp.length; i++)
if (tmp[i - 1].isBold != tmp[i].isBold) {
result.add(tmp[i]);
resultIdx++;
}
else
result[resultIdx].text = result[resultIdx].text
+ tmp[i].text;
}
return result;
}
}
class TextPart{
String text;
bool isBold;
TextPart(this.text, this.isBold);
}
Not fully tested but you can try this helper function that uses Text.rich and takes in the fullText and the textToBold then returns a Text:
static Text boldTextPortion(
String fullText,
String textToBold,
) {
final texts = fullText.split(textToBold);
final textSpans = List.empty(growable: true);
texts.asMap().forEach((index, value) {
textSpans.add(TextSpan(text: value));
if (index < (texts.length - 1)) {
textSpans.add(TextSpan(
text: textToBold,
style: const TextStyle(fontWeight: FontWeight.bold),
));
}
});
return Text.rich(
TextSpan(
children: <TextSpan>[...textSpans],
),
);
}
RichText()
Or if you receiving text from for example 'someText'.tr,
so use styled_text pub package.