Related
I have searched a lot but I can't find a solution for this specific problem:
So I want to display a text in my flutter application. But this text shall be variable, so I integrated Firebase to my project. And everything is working well, so I already managed to show images from Firebase but I really don't know how to display a text.
Can you please show me how to do this? Maybe someone could show me the code I need to use to make this work?
This is my code so far, I didn't integrate the specific code to communicate with my Firebase backend, because I don't know how to do this.
import 'package:flutter/material.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
class MapsPage extends StatefulWidget {
MapsPage({Key key}) : super(key: key);
#override
_MapsPageState createState() => _MapsPageState();
}
class _MapsPageState extends State<MapsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Firebase'),
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFBD23E), Color(0xffF6BE03)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter),
),
),
),
body: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xffFEFDFD), Color(0xffBDBDB2)],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
text: 'Some text',
children: [
TextSpan(
text:
'I want this TextSpan to be variable. So if I change the data in my Firestore Database this text shall also change.',
),
TextSpan(
text: 'And some more text.',
),
],
),
),
),
],
),
),
);
}
}
Can you please help me? Thank you so much!!
Below is a screenshot of my firestore.
.
// This below returns the text
Future<Map<String, dynamic>> getData() async {
DocumentReference<Map<String, dynamic>> document =
FirebaseFirestore.instance.doc('KBADatum/6j5Fnvj0gNkSCRIx7ecH'); // path to doc
DocumentSnapshot<Map<String, dynamic>> query = await document.get();
print(query.data());
return query.data();
}
// and this is how you consume it.
FutureBuilder<Map<String, dynamic>>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
if (snapshot.hasError) return CircularProgressIndicator();
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
return RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
text: 'Some text',
children: [
TextSpan(
text: snapshot.data['DatumJahr'], // first text
),
TextSpan(
text: 'And some more text.',
),
],
),
);
},
)
The snapshots() method provides a stream which you can subscribe to get the latest document changes. To update your ui using the stream, you can use StreamBuilder which builds itself based on the latest snapshot of interaction.
One final thing is that you can't use StreamBuilder as a child to a TextSpan. So, you will either rebuild the RichText widget or use WidgetSpan to rebuild only the span when there is an event on your stream.
Here is an example:
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
text: 'Some text',
children: [
// Use WidgetSpan instead of TextSpan, which allows you to have a child widget
WidgetSpan(
// Use StreamBuilder to listen on the changes of your Firestore document.
child: StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection('my_collection')
.doc('my_document')
.snapshots(),
builder: (context, snapshot) {
final document = snapshot.data; // Get the document snapshot
final text = document?.data()?['my_text']; // Get the data in the text field
return Text(text ?? 'Loading...'); // Show loading if text is null
},
),
),
TextSpan(
text: 'And some more text.',
),
],
),
)
Note: I tried to keep the example simple as far as possible, but you can learn more about StreamBuilder to handle errors/data and the state of connection.
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 ##
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.
Flutter when I used ListTile ThreeLines, I don't know how to use ThreeLine
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('ddd'),
),
body:Container(
child: Column(
children: <Widget>[
ListTile(
isThreeLine: true,
leading: Icon(Icons.event_note),
title: Text('Title 1'),
// subtitle: Text('Title2'),
subtitle: Column(
children: <Widget>[
Text('Titile2'),
Text('Title 3'),
Text('Title 4'),
Text('and so on')
],
),
)
],
),
) ,
),
);
}
}
When i delete isThreeLines, the code is Ok
ListTile
Thanks
As from the docs:
The value of subtitle, which is optional, will occupy the space
allocated for an additional line of text, or two lines if isThreeLine
is true.
It basically means the subtitle of the ListTile is given more space to have text which is more than one line in length:
By default, the ListTile in flutter can display only 2 lines. The Title and the SubTitle. In case there is a third line of text to be displayed, the isThreeLine is set to true and can allow another line to be present. The subtitle will be taking care of giving the 3rd line of text. It is expected that, if the isThreeLine is set to true, the subtitle should be non-null. Anything after "\n" inside subtitle will come in next line
ListTile(
title: Text("First Line",
style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text("Second One Text "\nThis is Line Third Text"),
isThreeLine: true,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
GestureDetector(
child: Icon(Icons.delete,color: Colors.red,),
onTap: () {
},
),
],
),
onTap: (){},
)
By default, the ListTile in flutter can display only 2 lines. The Title and the SubTitle. In case there is a third line of text to be displayed, the isThreeLine is set to true and can allow another line to be present. The subtitle will be taking care of giving the 3rd line of text. It is expected that, if the isThreeLine is set to true, the subtitle should be non-null.
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.