【问题标题】:Call a function inside a TextSpan? - Flutter在 TextSpan 中调用函数? - 颤振
【发布时间】:2021-11-27 23:58:53
【问题描述】:

我想在TextSpan 中调用函数checkProportion()。有可能吗?

这是我想要包含该函数的代码:

 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,
                  ),
            ),
            //...

编辑:

我想强调颜色配置可能会发生变化(并不总是相同的比例)以及 TextSpans 也会发生变化。条件是:

  • 如果包含'A'和'P',则颜色为棕色
  • 如果它包含 'A' 和 'pp',则颜色为 黑色
  • 如果包含'aa',则颜色为white

下面的图片会让它更清楚:

示例 1:

示例 2:

【问题讨论】:

  • 颜色排列是如何决定的?例如,在您的 9:3:4 情况下,为什么那些 3 是黑色的,而不是其他任何 3?
  • 这是因为这3个包含'A'和'pp'。我在图片之前列出了带有项目符号的条件,以便您更好地查看
  • 好的,看起来你想从输入数据中获取比例,除了绘制16个文本。请参阅我的更新答案。
  • 看起来和我想要达到的效果很接近,但是我还没有测试代码。我只是想知道final: data[]:就我而言,16 个结果中的每一个都发生了变化(例如:现在第一个是 AAPP,但它也可以是 aaPp,具体取决于用户在应用程序上一页上的输入)。只是您将 16 个小部件中的每一个都放置为不会更改的固定字符串。我应该写widget1widget2...吗?
  • 如果您有多个数据点,最好将业务逻辑重构为一个小部件,以提高代码的可重用性。我在答案中提供了一个例子。

标签: android flutter dart mobile


【解决方案1】:

当用户点击TextSpan时如何调用函数:

TapGestureRecognizer 传递给recognizer 属性,例如:

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();
    },
); 

编辑:

根据您对问题的最新编辑,完成此任务的最佳方法是提升根据遗传密码确定颜色的功能(我只是将其称为getColorFromCode,您可以将其称为@987654330 @ 管他呢)。这样,您可以在需要时计算“比例”。

我做了一个小演示项目给你看如何在两个不同的小部件中调用辅助函数:一个显示比例,另一个显示16个不同颜色的代码。

看起来是这样的:

要运行演示,请创建一个新的 Flutter 项目并将其整个 main.dart 文件替换为以下代码:

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
}

再次编辑:

如果您有多个数据,您还可以将业务逻辑重构为一个独立的小部件,这样您就可以轻松地重用代码。

例如,我们可以传入 3 组数据并构建如下内容:

完整源代码:

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
  }
}

【讨论】:

  • 我的情况是在加载TextSpan 时。问题是我在children 中有 16 个 TextSpan。我必须为每个 TextSpan 调用这个函数(我知道我应该做一个列表,但我是初学者,没有信心)。我对使您的代码适应我的代码有点困惑。你能帮我解决这个问题吗?
  • @bilbo_bo 虽然我可以帮助您,但最好退后一步讨论您最终想要实现的目标。可能有一个XY Problem:除了使用 16 个 TextSpan 和调用函数之外,可能还有更好的方法来实现您想要实现的目标。
  • 问题是 16 个 TextSpan 具有特定的颜色(例如:可能有 9 个棕色、4 个黑色和 3 个白色)。我试图编写的函数是给出比例(例如Proportion: 9:4:3)。所以我想为每个TextSpan调用函数。收到了吗?
  • @bilbo_bo 好的,我根据您的 cmets 编辑了我的答案。如果不够清楚,您可以编辑您的问题并上传几张图片来展示您想要实现的目标。
  • 嘿,我刚刚编辑了我的问题以使其更清楚。
【解决方案2】:

如果您想在点击 TextSpan 小部件时调用函数,则可以使用 WidgetSpan 并使用 InkWell 包装文本小部件,如下所示:

WidgetSpan(
  child: InkWell(
    onTap: () => checkPropportion(),
    child: Text(
      widget.result + '  ',
      style: TextStyle(
        fontSize: 20.0,
        fontWeight: FontWeight.bold,
        color: checkdominantA(widget.predominant, widget.result),
        height: 2.5,
        letterSpacing: 0.7,
      ),
    ),
  )
),

【讨论】:

  • 我其实是想在加载TextSpan的时候调用函数
  • 有没有办法做到这一点?
猜你喜欢
  • 1970-01-01
  • 2020-08-02
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多