In flutter what is the use ".." instead of "."? - flutter

Gesture detection in Flutter TextSpan I found this code
import 'package:flutter/gestures.dart';
...
new RichText(
text: new TextSpan(text: 'Non touchable. ', children: [
new TextSpan(
text: 'Tap here.',
recognizer: new TapGestureRecognizer()..onTap = () => print('Tap Here onTap'),
)
]),
);
Why here double dot ".." is used to access onTap and why It's giving error when I use "." (single dot).

Double dots(..) i.e cascade operator
“.. ”is known as cascade notation(allow you to make a sequence of operations on the same object). It allows you to not repeat the same target if you want to call several methods on the same object.This often saves you the step of creating a temporary variable and allows you to write more fluid code.
Normally, we use the below way to define several methods on the same object.
var tapGes = TapGestureRecognizer()
tapGes.onTap = func()
var tapGes = TapGestureRecognizer()
..onTap = func()
...
TextSpan(
text: 'Tap here.',
recognizer: tapGes,
)
...

Related

How to hide password ENTIRELY in flutter [duplicate]

This question already has answers here:
Flutter: obscureText, how to stop showing typed characters
(2 answers)
Closed last year.
I was searching a lot on the internet about how to hide password in TextFormField, the entirely one. Because obscureText doesn't hide all of it, they give a slightly every character you typed
screenshot
Is there any solution for this? Thx in advance
You need it on Android and iOs, right? Because on other platforms seems to be implemented by default like you want it.
In any case, try this:
class ObscuringTextEditingController extends TextEditingController {
ObscuringTextEditingController(String text) : super(text: text);
#override
TextSpan buildTextSpan({required BuildContext context, TextStyle? style, required bool withComposing}) {
var displayValue = '•' * value.text.length;
if (!value.composing.isValid || !withComposing) {
return TextSpan(style: style, text: displayValue);
}
final TextStyle composingStyle = style?.merge(
const TextStyle(decoration: TextDecoration.underline),
) ??
const TextStyle(decoration: TextDecoration.underline);
return TextSpan(
style: style,
children: <TextSpan>[
TextSpan(text: value.composing.textBefore(displayValue)),
TextSpan(
style: composingStyle,
text: value.composing.textInside(displayValue),
),
TextSpan(text: value.composing.textAfter(displayValue)),
],
);
}
}
Updated the original code from here

How to use a TextSpan as a Widget inside VisibilityDetector

I have text in my app that I want to color differently as time goes on. I did this by using RichText widget with a separate text span for each character and a timer that will then update the the state and repaint all of the text spans appropriately. This works so long as the text isn't too long. It starts to break at around 7-10k characters text.
In order to optimize this I decided to use the VisibilityDetector library because text that isn't visible doesn't need to be colored differently. So I chunked the text and put each chunk in its own visibility detector, and when it isn't visible I just set the text using a Text widget. This works, but a single line will get cut off halfway through and start on the next line since they're separate widgets.
What I would like to do is pass the TextSpan as a child of the VisibilityDetector, but this gives the error that TextSpan is not a subtype of the type Widget. Is there any way to do what I want to do?
This is the type of widget tree I would like to have:
String myText = '';
RichText(
text: TextSpan(
children: myText.chunk().mapIndexed((chunkIndex, chunkText) {
return WidgetSpan(
child: VisibilityDetector(
onVisibilityChanged: (info) => _handleVisibilityChanged(),
child: !chunkIsVisible ?
Text(chunkText) :
TextSpan( //This breaks because its not a subtype of Widget
children: chunkText.characters.mapIndexed((charIndex, char) {
return TextSpan(
text: char,
style: _styleTextBasedOnIndex((chunkIndex * ChunkSize) + charIndex)
)
}
)
)
)
}
)
)
I think you can do this to pass the error:
String myText = '';
RichText(
text: TextSpan(
children: myText.chunk().mapIndexed((chunkIndex, chunkText) {
return WidgetSpan(
child: VisibilityDetector(
onVisibilityChanged: (info) => _handleVisibilityChanged(),
child: !chunkIsVisible ?
Text(chunkText) :
RichText(text: TextSpan( // Use another RichText
children: chunkText.characters.mapIndexed((charIndex, char) {
return TextSpan(
text: char,
style: _styleTextBasedOnIndex((chunkIndex * ChunkSize) + charIndex)
)
}
)
)
)
)
}
)
)

Flutter WidgetTest cannot click on TextSpan

Very new to flutter WidgetTest and could not find a solution to a problem I am having. When dealing with TextSpan objects for WidgetTests, I'm unable to tap on the object.
UI Code
RichText(
text: TextSpan(
text: "First piece of text",
children: [
TextSpan(
text: "Text I want to tap in widget text",
recognizer: TapGestureRecognizer()
..onTap = () {
// go to another page i want to look for a text widget on
}),
],
),
)
WidgetTest code
Future<void> textSpanTap(WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(home: signInPage));
await tester.tap(find.text("Text I want to tap in widget text"));
}
Any insight on this would help.
Initially I started with the similar question here: Finding a TextSpan to tap on with Flutter tests
.
But the solution from there proved to be non-reliable (worked, but for any configuration).
I ended up using the suggested workaround from here:
https://github.com/flutter/flutter/issues/56023#issuecomment-764985456

Flutter RichText or other markup of dynamic content

I'm trying to display formatted text that is created dynamically in the app. It is the result of a diff calculation and I can't see how RichText or any of the markdown formats would work. It doesn't seem like embedding HTML is the way to go, given that it seems that would display in a frame.
The code shows a static presentation of the code. I need to be able to use a list of objects and make an corresponding array of TextSpans. I'm not sure there is a way to do this.
I should add that the Styles I want are what you would see if editing text in MS Word: additions are colored green and deletions are red and crossed through. This part is easy in with RichText styles, but aren't supported by Markdown.
//This list of objects has the data I use will use to create the TextSpans.
List<DiffString> diffOut = diff(
oldStr,
newStr,
" ",
).pieces;
//
RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text: 'Hello ',
style: normalStyle,
),
TextSpan(
text: 'added',
style: addedStyle,
),
TextSpan(
text: 'deleted',
style: deletedStyle,
),
TextSpan(
text: ' \n\n',
style: normalStyle,
),
//TextSpan(text: 'default is messed up'),
],
),
),
pskink answered my question but then deleted it, so I'm posting it here. And yes, it just needed to map it like he said. Thanks!
/////////Here:
all you need is a List of TextSpans created by your diff calculation method and pass it as children: myListOfTextSpanDiffs - so for example: var myListOfTextSpanDiffs = diffOut.map(...).toList()

Is there an easy way to find particular text built from RichText in a Flutter test?

For example, I may have one RichText in current widget tree, that looks like
RichText(
text: TextSpan(
text: 'Hello ',
style: DefaultTextStyle.of(context).style,
children: <TextSpan>[
TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
TextSpan(text: ' world!'),
],
),
)
I try to use find.text('Hello bold world!') but it doesn't work because it's not a Text.
Framework solution
I have recently contributed this feature to the Flutter framework, i.e. to the built-in finders.
find.text()
You can now enable a findRichText parameter, which will then also find standalone RichText widgets:
find.text(
'Hello bold world!',
findRichText: true,
)
Simplest solution is to put a key on the RichText and read it that way.
If that's not a good fit for whatever reason, you can use find.byWidgetPredicate and pass a function that matches RichText widgets whose text.toPlainText() returns the string you want.
Here's the find.byWidgetPredicate call.
find.byWidgetPredicate((widget) => fromRichTextToPlainText(widget) == 'Hello bold world!')
Here's the fromRichTextToPlainText helper function. Pass it the RichText widget, it will return the plain text.
String fromRichTextToPlainText(final Widget widget) {
if (widget is RichText) {
if (widget.text is TextSpan) {
final buffer = StringBuffer();
(widget.text as TextSpan).computeToPlainText(buffer);
return buffer.toString();
}
}
return null;
}
I solved for this by digging into the widget a bit more manually
final richTextWidget = tester.element(richTextFinder).widget as RichText;
print(richTextWidget.text.children);
With the children, I can assert they are generated as expected