Флаттер: изменение текстового стиля TextSpan с помощью TapGestureRecognizer - PullRequest
2 голосов
/ 25 апреля 2019

Я хотел бы сделать каждое слово текста кликабельным. Затем при нажатии на определенное слово его цвет текста должен измениться.

Создание каждого кликабельного слова прекрасно работает Тем не менее, цвет текста не меняется, когда я нажимаю на слово. Вот как далеко я зашёл:

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 Ответ

1 голос
/ 25 апреля 2019

Первая проблема в том, что у вас есть isPressed внутри метода _buildTextSpanWithSplittedText, который будет перезаписываться при каждой перерисовке.И если вы сохраните эту переменную на уровне класса, она будет применена ко всем TextSpans.Таким образом, возможное решение может быть с использованием 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 в качестве обратного вызова для этого решения.Надеюсь, что это поможет.

...