Text widget with wrong emoji on initialization in Flutter - flutter

I want to display an emoji within a text widget, using Flutter.
When I copy an example emoji from the internet, some of them shows up with 2 characters in my IDE.
E.g:
static String dualCharEmoji = "⚔️";
static String singleCharEmoji = "🗡";
When I use this variable in the text widget, both of them work fine:
Text("⚔️",)
Text("🗡",)
However, only when first running the app, the dual character emoji shows up as its first character only.
i.e. Only when first opening the app, the sword icon shows up as ⚔ instead of as ⚔️
After it gets reloaded it gets fixed, and hot reloading/hot restarting does not makes it bug again.
My question is:
Is this a bug? Am I missing some detail here? Why does it only happen when first opening the app?
How can I show a 2 sized emoji from the start?
I'm using the following Flutter version:
>flutter --version
Flutter 1.9.1+hotfix.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision cc949a8e8b (9 weeks ago) • 2019-09-27 15:04:59 -0700
Engine • revision b863200c37
Tools • Dart 2.5.0
See the minimum reproducible example below:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static String dualCharEmoji = "⚔️";
static String singleCharEmoji = "🗡";
String text = dualCharEmoji;
int count = 0;
void swapText() {
setState(() {
if (count % 2 == 0)
text = singleCharEmoji;
else
text = dualCharEmoji;
count++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
text,
style: TextStyle(fontSize: 50),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: swapText,
),
);
}
}

After creating this question, doing many unsuccessful tries, and no working answer, I've created an issue on Flutter's official Github repository.
After I showed my problem, an user explained that that is a bug related to how Flutter renders and caches the fonts, in case of the default font cannot handle properly some character:
The first time that dualCharEmoji is rendered Flutter sees that the default font does not handle the 2694 character. [...]it can render the basic 2694 crossed swords character but not the 2694 FE0F emoji.
When singleCharEmoji is rendered Flutter now includes the NotoSansSymbols font in the list of fonts given to the HarfBuzz text shaper.[...] and matchFamilyStyleCharacter returns NotoColorEmoji. Flutter also adds this font to the cache.
The next time the engine tries to render dualCharEmoji it provides both cached fonts (NotoSansSymbols and NotoColorEmoji) to HarfBuzz. Now that HarfBuzz is aware of the sequences defined in NotoColorEmoji it can recognize the 2694 FE0F emoji and return it to Flutter.
I've referenced here only some parts of the discussion. You can read the full discussion and explanation on the issue page I've linked above.
Users suggested some workarounds, namely two:
First, you can force the engine to pre-cache a font that handles emojis correctly. You can do this by adding the following code in the build, or the initState method (anywhere that runs before building the Text Widget):
import 'dart:ui';
ParagraphBuilder pb = ParagraphBuilder(ParagraphStyle(locale: window.locale));
pb.addText('\ud83d\ude01'); // smiley face emoji
pb.build().layout(ParagraphConstraints(width: 100));
This worked on my example project, but as stated on the Issue page:
However, this relies on implementation details of the current Flutter text engine that may change in the future.
So be aware that this workaround can stop working at any given time.
The second workaround is given as follow:
For now the work around is to list the desired font in the text style and it will be resolved correctly.
Which is simply to give a TextStyle property to the Text Widget, with its fontFamily (or the fontFamilyFallback) property set. The chosen font must already support all characters required. This also worked for me, however I had to include a custom font from my computer (or from a public online package).

Related

Flutter Web shows emojis in black&white

The bounty expires in 3 days. Answers to this question are eligible for a +50 reputation bounty.
mirkancal wants to draw more attention to this question.
In ios/android apps emojis are shown correctly. But using any web-browser (e.g. Chrome) the emoji appears in black and white. I also tried different Font-Families but with the same result.
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text('Enjoy! 🥳 If there\'s any question')
),
);
}
}
Use Noto Color Emoji from google (follow this steps):
Download the font Download Noto Color Emoji
Added it to pubspec.yaml `flutter:
fonts:
family: Noto Color Emoji
fonts:
asset: assets/fonts/NotoColorEmoji-Regular.ttf`
And in TextStyle class use it like this TextStyle( fontFamilyFallbackm: [ 'Apple Color Emoji', 'Noto Color Emoji', ], )
Unlike that try to:
. Delete web folder
. Update flutter by using command flutter upgrade
. Run command flutter create .

WebView on Flutter Web Not working with external library

currently I am developing an app using Flutter Web and I've been trying to use this library which does not have a lot of documentation.
I've tried the example provided but for some reason it's not working
In the example there is no onLoaded() {} function method and without that I get an error saying that I have to implement it.
Finally, if I want to set the width and height of the website I should call setState(). How do I do that?
Link to the library https://pub.dev/packages/easy_web_view2
Code: (I'm running main() in another file)
import 'package:flutter/material.dart';
import 'package:easy_web_view2/easy_web_view2.dart';
class Quiz extends StatelessWidget {
const Quiz({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('CyberQuiz'),
),
body: EasyWebView(
src: 'https://www.ncsc.gov.uk/',
onLoaded: () {
print('Loaded!!');
},
),
);
}
}
A bit of an unobvious issue. I was trying to embed a government website. Apparently you are not allowed to do that.
I am also using a different library which is called webviewx. It has better documentation than the other one

About the benefits of const for Stateles widget in Flutter

There is a custom appbar:
class _MyAppBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SliverAppBar(
title: Text('Catalog', style: Theme.of(context).textTheme.headline1),
...
);
}
}
and usage of it
return Scaffold(
body: CustomScrollView(
slivers: [
_MyAppBar(),
const SliverToBoxAdapter(child: SizedBox(height: 12)),
...
In that code const using wildly (it's the Flutter team code as an example of a particular package usage) and why in this case const isn't used for _MyAppBar() (we could add const constructor in _MyAppBar definition)?
When you create a widget and is able to prefix it with const that widget will not rebuild. The framework knows not to rebuild such widgets because it can tell that the objects did not change. Constant objects are resolved at compile-time, and due to a process known as canonicalization if two or more objects have the same parameters, and are constant, they will refer to the same instance.
For example, if you have
#override
Widget build() {
const MyWidget();
}
And then somewhere you call setState, MyWidget will not be reconstructed because it was already resolved at compile-time, and the framework will also not call its build method which makes sense because non of the arguments passed to MyWidget (which are none here) has changed as a result of issuing the rebuild so the configuration is still the same.
Moreover if somewhere else you call const MyWidget(); you will still refer to the same object/instance so it's more optimal.
And they added the lint rule so that people add a const constructor and are able to invoke their widgets/classes with const and it uses by default in flutter. Flutter apps, packages, and plugins created with flutter create starting with Flutter version 2.3.0 are already set up to use the lints defined in this package.
Disabling individual rules
include: package:lints/recommended.yaml
linter:
rules:
avoid_shadowing_type_parameters: false
await_only_futures: true
For more read this analysis option and const keyword.
After reading this, it would be helped you to understand why in your case const isn't used for _MyAppBar().
SRC From: remove const
when you use const behind widgets it changes the way it is rebuilt it will not rebuild completely from scratch when you setState the widget.it uses the data that has been stored on ram and rebuilds it with that.
when your widget does not change with rebuilding the page it is recommended to improve the application behavoiur

How to use drawBox, drawEllipse or drawLine methods within the Dart / Flutter pdf library

I want to generate PDF files including self drawn graphics within a Flutter App. Of course with the pdf library provided it is quite simple to show a pdf preview containing for example two text lines, but i want to be able to insert some graphics that i want to draw myself, as i need to draw (myself)some very unconventional graphs. In order to do that i need to be able to draw within a pdf widget (some lines, curves, points, of several colors, etc...). As per now i didn't manage to even draw a point !!!, the pdf library of flutter dart describes dozens of methods, but doesn't show any example, that's a pitty in fact. Is there somebody who could help me in order to "draw" graphics within PDF Dart Flutter Object. The PdfLibrary includes PdfGraphics class that is supposed to have the methods i try tu use without success !!
Many thank's in advance
Please find my code :
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
void main() => runApp(const MyApp('Ceci est mon premier PDF'));
class MyApp extends StatelessWidget {
const MyApp(this.title);
final String title;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text(title)),
body: PdfPreview(
build: (format) => _generatePdf(format, title),
),
),
);
}
Future<Uint8List> _generatePdf(PdfPageFormat format, String title) async {
final pdf = pw.Document();
pdf.addPage(
pw.Page(
pageFormat: format,
build: (context) {
return pw.Center(
child: pw.Column (
children: [
pw.Text(title),
pw.Text(title),
//pw.drawBox(10,10,100,100), <---- if i remove the comment the app
crashes saying "Method not found"
otherwise i have a PDF generated with two
lines of text, and i want that just under a
self drawn graphic could be displayed
],
),
);//pw.Text(title),
},
),
);
return pdf.save();
}
}
You have to use the CustomPaint class instead of just drawing directly.
Try
pw.CustomPaint(
size: const PdfPoint(110, 110),
painter: (PdfGraphics canvas, PdfPoint size) {
canvas
..setColor(PdfColors.indigo)
..drawRect(10, 10, 100, 100)
..fillPath();
},
);
instead of
pw.drawBox(10,10,100,100)
Check out the list of drawable shapes here: https://pub.dev/documentation/pdf/latest/pdf/PdfGraphics-class.html
For those looking for more information
(pdf's) CustomPaint expects a child and one or two painter functions. Unlike Flutter's CustomPaint
this uses a PdfGraphics instead of a Canvas
the painting functions are functions not CustomPainters
I struggled for days to figure this out and found my answer on this comment: https://github.com/DavBfr/dart_pdf/issues/145#issuecomment-530798498

What is the universal range of the user defined textScaleFactor in Flutter?

After my fruitless search for the expected range of the textScaleFactor parameter I attempted to answer my q by printing...
MediaQuery.textScaleFactorOf(context);
2 times while debugging on my Note 9: The output was 0.8 & 2 when I set the font size (in my accessibility settings) # its min & max, resp..
My q is: Can I expect this to be the universal range across all devices?
If you're unsure, I would certainly accept an answer from someone posting their own test results (especially if they were to test on iphone).
On the iOS simulator and my iPhoneXS Max the default is 1.0
Even when Display View setting is Zoomed or Standard.
When I go to Accessibility and change the size to the max available size (step by step):
flutter: text scale 1.1176470588235294
flutter: text scale 1.2352941176470589
flutter: text scale 1.3529411764705883
If i check the toggle for the "Larger Accessibility Sizes", the max I get:
flutter: text scale 3.1176470588235294
Going down with the slider in Accessibility (only 3 steps available):
flutter: text scale 0.9411764705882353
flutter: text scale 0.8823529411764706
flutter: text scale 0.8235294117647058
I don't know how useful those values can be to you, but to answer your questions you SHOULD NOT expect min=0.8 & max=2 ...
In any case, if you need to constrain the factor somehow, as I don't know any way to inject them in the MediaQuery that MaterialApp uses, you should have a custom function that normalizes the MediaQuery.textScaleFactorOf(context), maybe at the root of your widget tree, and manually apply that to each Text::textScaleFactor ?
Someone already provided a satisfactory answer to the question; this is just me expanding on their closing remarks:
In any case, if you need to constrain the factor somehow, as I don't know any way to inject them in the MediaQuery that MaterialApp uses, you should have a custom function that normalizes the MediaQuery.textScaleFactorOf(context), maybe at the root of your widget tree, and manually apply that to each Text::textScaleFactor ?
I ended up using the following code to constrain textScaleFactor within 0.8-2.0; I added an extra constraint where the result will always be a multiple of 0.1:
import 'package:flutter/material.dart';
import 'dart:math';
import 'authentication-page.dart';
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
builder: (context, child) {
onLayout(context);
return MediaQuery(
child: child,
data: MediaQuery.of(context).copyWith(textScaleFactor: max(0.8, min(2.0, (10*MediaQuery.textScaleFactorOf(context)).round()/10))));
},
title: 'Flutter Demo',
home: AuthenticationPage(),
);
}
}