Call a function inside a TextSpan? - Flutter
How to call a function when user taps on a TextSpan
:
Pass a TapGestureRecognizer
to recognizer
property, for example:
TextSpan(
text: "hello world",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.blue,
height: 2.5,
letterSpacing: 0.7,
),
recognizer: TapGestureRecognizer()
..onTap = () {
print("TextSpan is clicked.");
// callMyFunction();
},
);
Edit:
Based on your newest edits in the question, the best way to approach this task is to lift up the function that determines color based on the genetic code (I'm just calling it getColorFromCode
, you can call it checkdominant
or whatever). This way, you can calculate "proportion" when needed.
I've made a small demo project for you to see how to call the helper function in two different widgets: one displays the proportion and the other one displays the 16 codes in various colors.
This is how it looks like:
To run the demo, create a new Flutter project and replace its entire main.dart
file with the code below:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final data = [
'AAPP', 'AApP', 'aAPP', 'aApP',
'AAPp', 'AApp', 'aAPp', 'aApp',
'AaPP', 'AapP', 'aaPP', 'aapP',
'AaPp', 'Aapp', 'aaPp', 'aapp',
];
@override
Widget build(BuildContext context) {
final colors = data.map(getColorFromCode);
final browns = colors.where((color) => color == Colors.brown).length;
final blacks = colors.where((color) => color == Colors.black).length;
final whites = colors.where((color) => color == Colors.white).length;
return Scaffold(
appBar: AppBar(title: Text('Flutter Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Proportion: $browns:$blacks:$whites'),
Container(
width: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue, width: 4.0),
borderRadius: BorderRadius.circular(16),
color: Colors.lightGreen,
),
padding: EdgeInsets.all(16),
child: RichText(
text: TextSpan(
children: [
for (final code in data)
TextSpan(
text: '$code ',
style: TextStyle(
color: getColorFromCode(code),
fontFamily: 'courier',
),
),
],
)),
),
],
),
),
);
}
}
Color getColorFromCode(String code) {
if (code.contains('A') && code.contains('P')) return Colors.brown;
if (code.contains('A') && code.contains('pp')) return Colors.black;
if (code.contains('aa')) return Colors.white;
return Colors.red; // not covered in the question description
}
Edit again:
If you have more than a few data, you can also refactor the business logic into a standalone widget, so you can reuse the code easily.
For example, we can pass in 3 sets of data and build something like this:
Full source code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final data1 = ['AAPP', 'AApP', 'aAPP', 'aApP', 'AAPp', 'AApp', 'aAPp'];
final data2 = ['AaPP', 'AapP', 'aaPP', 'aapP', 'AaPp', 'Aapp', 'aaPp'];
final data3 = ['aaPp', 'AapP', 'aAPP', 'aApP', 'AaPp', 'aaPP'];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Flutter Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(MyWidget.getProportion(data1)),
MyWidget(data: data1),
Divider(),
Text(MyWidget.getProportion(data2)),
MyWidget(data: data2),
Divider(),
Text(MyWidget.getProportion(data3)),
MyWidget(data: data3),
],
),
),
);
}
}
class MyWidget extends StatelessWidget {
final List<String> data;
const MyWidget({Key? key, required this.data}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue, width: 4.0),
borderRadius: BorderRadius.circular(16),
color: Colors.lightGreen,
),
padding: EdgeInsets.all(16),
child: RichText(
text: TextSpan(
children: [
for (final code in data)
TextSpan(
text: '$code ',
style: TextStyle(
color: getColorFromCode(code),
fontFamily: 'courier',
),
),
],
)),
);
}
static String getProportion(List<String> data) {
final colors = data.map(getColorFromCode);
final browns = colors.where((color) => color == Colors.brown).length;
final blacks = colors.where((color) => color == Colors.black).length;
final whites = colors.where((color) => color == Colors.white).length;
return 'Proportion: $browns:$blacks:$whites';
}
static Color getColorFromCode(String code) {
if (code.contains('A') && code.contains('P')) return Colors.brown;
if (code.contains('A') && code.contains('pp')) return Colors.black;
if (code.contains('aa')) return Colors.white;
return Colors.red; // not covered in the question description
}
}
bilbo_bo
Updated on January 01, 2023Comments
-
bilbo_bo over 1 year
I want to call a function
checkProportion()
inside aTextSpan
. Is it possible?Here is the code that I want to include the function:
child: RichText( text: TextSpan( children: [ TextSpan( text: widget.result + ' ', style: TextStyle( fontSize: 20.0, fontWeight: FontWeight.bold, color: checkdominantA(widget.predominant, widget.result), height: 2.5, letterSpacing: 0.7, ), ), //...
Edit:
I want to highlight that the color configuration might change (it is not always the same proportion) as well as the TextSpans change too. The conditions are:
- If it contains 'A'and 'P' the color is brown;
- If it contains 'A' and 'pp' the color is black;
- If it contains 'aa' the color is white;
The following images are going to make it clearer:
Example 1:
Example 2:
-
WSBT over 2 yearsHow are the color arrangement decided? For example, in your 9:3:4 case, why are those 3 in black, not any other 3?
-
bilbo_bo over 2 yearsIt's because these 3 contains 'A' and 'pp'. I listed the conditions with bullet points right before the images so you can see it better
-
WSBT over 2 yearsOK, it looks like you want to get the proportion from the input data, in addition to drawing 16 texts. See my updated answer.
-
bilbo_bo over 2 yearsIt seems that it's pretty close to what I want to achieve, but I didn't test the code yet. I'm just wondering about the
final: data[]
: in my case, each of the 16 results changes (e.g.: now the first one is AAPP but it can also be aaPp depending on the input of the user on the previous page of the app). It's just that you put each of the 16 widgets as fixed Strings that don't change. Should I writewidget1
,widget2
... instead? -
WSBT over 2 yearsIf you have more than a couple of data points, it's better to refactor the business logic into a widget, to increase code reusability. I provided an example in the answer.
-
bilbo_bo over 2 yearsI see what you mean, but what I was trying to say is that each result is a separate widget. It is organized in this way: widget.result, widget.result2, widget.result3 ... widget.result16. There are a lot of combinations and it's almost impossible to list all of them. What I was asking is if I should put
final data = [widget.result, widget.result2 ... widget.result16]
-
WSBT over 2 yearsYes, that should work.
-
bilbo_bo over 2 yearsI was trying to do it like I said in my last message but here it says that The instance member 'widget' can't be accessed in an initializer.
-
bilbo_bo over 2 yearsI tried searching for this error but none of the solutions fit in my case
-
WSBT over 2 yearsWithout seeing your full code, I'm not sure where you are putting that line to get the error. You can try to add
late
in the beginning, so it's likelate final data = ...
. If it doesn't work, you could ask a new question and post the relevant source code.
-
bilbo_bo over 2 yearsI actually want to call the function when the TextSpan is loaded
-
bilbo_bo over 2 yearsIs there a way to do this?
-
bilbo_bo over 2 yearsMy case is when
TextSpan
is loaded. The thing is that I have 16 TextSpans insidechildren
. I have to call this function for each TextSpan (I know I should've done a list but I'm a beginner and felt no confidence). I'm a bit confused about adapting your code to mine. Could you help me with that? -
WSBT over 2 years@bilbo_bo While I could help you with that, it might be better to take one step back and discuss what you ultimately want to achieve. There could be an
XY Problem
: there might be a better way to do what you want to achieve, other than using 16 TextSpans and calling functions. -
bilbo_bo over 2 yearsThe thing is that the 16 TextSpans have specific colors (for example: there could be 9 browns, 4 blacks and 3 whites). The function that I was trying to write was to give the proportion (e.g.
Proportion: 9:4:3
). So I thought about calling the function for eachTextSpan
. Did you get it? -
WSBT over 2 years@bilbo_bo Okay, I edited my answer based on your comments. If it's not clear enough, you can edit your question and upload a few pictures demonstrating what you want to achieve.
-
bilbo_bo over 2 yearsHey, I've just edited my question to make it more clear.