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
Related
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
I was wondering if there was a way to customize a TextFormField with more accuracy. I don't want to change the whole text color, but only part of it. For instance, below is the above mention TextFormField and I want to highlight "には" (ie what is between curly braces) by adding a red color. I would like to avoid creating multiple TextFormFields to do this because it will be a mess to assemble the text afterwards but I don't know if it is possible.
WARNING
I am not looking for the RichText widget since I want to customize a TextFormField Widget or any Widget with an editable text.
This Widget is used in a List so I would like not to use a "preview" widget with my input widget.
AND
I don't need a full RichTextEditor since the User should not be able to modify the color. Only parts between curly braces should automatically be colorised.
Looking forwards to see what kind of solutions you guys could come up with !
I've finally found a gist that match my request. For those who are searching an answer to my question, you seems to have to override EditableText (How to change color of particular text in a text field dynamically?). But, it's only a draft and it is not working correctly as for today. I'll try to follow this path and add my answer on this post.
EDIT:
The only thing you have to change to this answer is the following:
#override
TextSpan buildTextSpan() {
final String text = textEditingValue.text;
int textLength = text.length;
if (widget.annotations != null && textLength > 0) {
var items = getRanges();
var children = <TextSpan>[];
for (var item in items) {
if (item.range.end < textLength) {
children.add(
TextSpan(style: item.style, text: item.range.textInside(text)),
);
} else if (item.range.start <= textLength) {
children.add(
TextSpan(
style: item.style,
text: TextRange(start: item.range.start, end: text.length)
.textInside(text)),
);
}
}
return new TextSpan(style: widget.style, children: children);
}
return new TextSpan(style: widget.style, text: text);
}
}
Explanation:
You simply have to correct the buildTextSpan part. The error was raised when you delete a character because the Range could raise an exception when the range end was not meet.
This might not be exactly what you want, but may be this can help you get started in a way.
Use RichText widget.
var text = new RichText(
text: new TextSpan(
style: new TextStyle(
fontSize: 10.0,
),
children: <TextSpan>[
new TextSpan(text: 'Text1'),
new TextSpan(text: 'Text2', style: new TextStyle(),
],
),
);
I am currently working on a project that requires minor animations to text as it appears in a TextFormField.
I hav extended the TextEditingControler and overriden the buildTextSpan function to enable different TextSyles based on the types of words that were being typed in. For example if a word is ['the','a','me'].
For example I would add a TextSpan with a particular style for each matching word and for all other words I would just add the word in a TextSpan with normal style.
This is working fine, however, what I want to do is to animate the matched words for a period as they are entered, for example they would turn from blue to green.
Extended TextEditingController Class
class RichTextEditingController extends TextEditingController {
TextStyle matchedStyle = TextStyle(
color: Colors.green,
fontSize: 20,
fontWeight: FontWeight.w700,
);
#override
TextSpan buildTextSpan({TextStyle style, bool withComposing}) {
List<String> wordsToMatchList = ['the','a','me'];
List<String> splitText = text.split(' ');
List<TextSpan> textSpanList = [];
splitText.forEach((word) {
if (wordsToMatchList.contains(word)) {
textSpanList.add(TextSpan(style: boldStyle, text: '$word'));
} else {
textSpanList.add(TextSpan(style: style, text: '$word'));
}
});
return TextSpan(children: textSpanList);
}
}
I have tried various techniques like future.Delayed and others, but can't seem to find any approach that works and need some help.
Question: Is there a way to add a minor animation to TextSpans or other widgets that would show when new text is typed into a text field that matches a certain pattern?
I am trying to add a default style to a Text Widget, but I need to be able to overwrite it.
this is what I am trying right now.
var newTitle = title;
if (title is Text) {
Text titleText = title as Text;
newTitle = Text(titleText.data, style: TextStyle == null ? TextStyle() : TextStyle(fontWeight: FontWeight.bold));
}
So I want to check if it has style if not add the default style to it, otherwise use overwriten
Flutter provides a simple way to do this by providing a DefaultTextStyle widget, which can be used to specify a default texty style for the subtree. If a child Text widget already defines a style, the specific Text style will be used.
DefaultTextStyle(
child: title,
style: TextStyle(fontWeight: FontWeight.bold),
),
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