Flutter:使用TapGestureRecognizer更改TextSpan的文本样式

4

我想让文本中的每个单词都可以点击。然后,当点击特定的单词时,它的文本颜色应该会改变。

让每个单词可以点击是可行的。然而,当我点击一个单词时,文本颜色似乎没有改变。这是我目前的进展:

import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';

 class MakeStringClickable extends StatefulWidget{
 @override
 State<StatefulWidget> createState() {
 // TODO: implement createState
 return _MakeStringClickableState();
 }
 }

class _MakeStringClickableState extends State<MakeStringClickable>{

String textToSplit = 'I would like to make each word clickable. On click of a particular word it's color should change.';

@override
Widget build(BuildContext context) {
return Scaffold(
  body: Container(
      alignment: Alignment.center,
      child: _buildTextSpanWithSplittedText(textToSplit, context)
  ),
);
}

RichText _buildTextSpanWithSplittedText(String textToSplit, BuildContext context) {
bool isPressed = false;
final splittedText = textToSplit.split(" ");
final spans = new List<TextSpan>();

  for(int i = 0; i <= splittedText.length - 1; i++ ){
    spans.add(TextSpan(
      text: splittedText[i].toString() + " ",
      style: TextStyle(color: isPressed ? Colors.black : Colors.red),
      recognizer: new TapGestureRecognizer()..onTap = () {
      setState(() {isPressed = !isPressed;});
      }
    ));
  }
  return RichText(text: TextSpan(children: spans));
}
}

当我点击一个单词时,我希望它的颜色改为黑色,但是样式更改似乎没有按预期工作。我希望有人能够帮助我。

1个回答

5

首先的问题是你在_buildTextSpanWithSplittedText内使用了isPressed,这将在每次重绘时被覆盖。如果你将该变量保持在类级别上,它将应用于所有。
因此,一个可能的解决方案是使用List,下面是一个示例:

import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart';

class MakeStringClickable extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MakeStringClickableState();
  }
}

class _MakeStringClickableState extends State<MakeStringClickable> {
  List<TapSection> sections;
  String textToSplit =
      'FirstWord would like to make each word clickable. On click of a particular word it\'s color should change.';
  TapGestureRecognizer r1;
  @override
  void initState() {
    sections = List<TapSection>();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        alignment: Alignment.center,
        child: _buildTextSpanWithSplittedText(textToSplit, context));
  }

  RichText _buildTextSpanWithSplittedText(
      String textToSplit, BuildContext context) {
    final splittedText = textToSplit.split(" ");
    final spans = List<TextSpan>();
    for (int i = 0; i <= splittedText.length - 1; i++) {
      var tapSection = TapSection(callBack: () {
        setState(() {});
      });
      sections.add(tapSection);
      spans.add(TextSpan(
          text: splittedText[i].toString() + " ",
          style: TextStyle(
              color: sections[i].isPressed ? Colors.black : Colors.red),
          recognizer: sections[i].recognizer));
    }
    return RichText(text: TextSpan(children: spans));
  }
}

class TapSection {
  TapGestureRecognizer recognizer;
  bool isPressed = false;
  final Function callBack;

  TapSection({this.callBack}) {
    recognizer = TapGestureRecognizer();
    recognizer.onTap = () {
      this.isPressed = !this.isPressed;
      this.callBack();
    };
  }
}

请注意,在此解决方案中,我们需要将setState作为回调函数进行调用。
希望这有所帮助。

2
太好了,它的运行方式正如我所想象的那样!非常感谢您的时间和帮助! :) 还有一个问题:我想一次只允许更改一个术语的颜色。因此,当我单击第二个术语时,它应该更改其颜色,并且我之前按下的术语应该将其颜色更改回默认值。我该如何操纵代码来实现这一点?我真的很感激进一步的帮助! - WeAreThePeople

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接