如何在Flutter的文本框中添加小部件(例如芯片或容器)

5
我有一个文本框小部件,用户将填写它。问题是除了填写文本外,用户还应该能够从一系列标签中选择,这些标签可以添加在文本之间(或末尾),示例情况如图所示(在图中,我使用了两个文本小部件和一个芯片,在实际情况下,它将是一个文本框而不是文本小部件)。

enter image description here

这里得到的解决方案并不能满足要求,因为它只添加了芯片而没有文本。我也尝试了扩展文本字段包,但也无法解决问题。有什么想法可以解决这个问题吗?


我没有使用过 Chips,但是你不能将实体完全分离吗?比如在一行中有文本 ("How to add a")、Chip 生成器小部件 ()、文本 ("in a text field")。没有任何代码,很难对此进行评论。 - Bilaal Abdel Hassan
不是Text小部件,而是TextField小部件。它将由用户填充,他可以在任何地方插入芯片。对不起,我没有这方面的工作代码。 - Pratheesh Russell
无所谓,原则不变。 Textfield(),Chip(),Textfield() - Bilaal Abdel Hassan
  1. 将有预定义关键词的按钮。点击它们将意味着插入带有该关键词的芯片,输入的其余单词将是字符串。一句话可能有多个芯片/关键词。
  2. 是的,我必须保存它。想法是将它们保存为json,主要文本将类似于“如何在文本字段中添加<<chip>>”,并且将有一个包含芯片字符串(按顺序)的json数组。但这只是一个基本想法,可能需要根据文本字段和芯片的显示方式进行更改。 希望我表达清楚了 @LonelyWolf
- Pratheesh Russell
问题已解决。我使用了扩展文本字段包。谢谢。 - Pratheesh Russell
显示剩余5条评论
1个回答

1

使用 extended_text_field 包。

结果:

每当出现 @ 符号时,它将在一个 Chip 中:

enter image description here

您需要扩展 SpecialTextSpanBuilder 并重写 build 方法:

class MySpecialTextSpanBuilder extends SpecialTextSpanBuilder {
  @override
  TextSpan build(String data,
      {TextStyle? textStyle, SpecialTextGestureTapCallback? onTap}) {
    final lookingFor = "@";
    final splitData = data.split(" ");
    final spans = splitData.map((e) {
      if (e == lookingFor) {
        return WidgetSpan(
          child: Chip(
            label: Text(e),
          ),
        );
      } else {
        return TextSpan(
          text: e,
          style: TextStyle(color: Colors.red),
        );
      }
    }).toList();
    return TextSpan(children: spans, style: textStyle);
  }

  @override
  SpecialText? createSpecialText(String flag,
      {TextStyle? textStyle,
      SpecialTextGestureTapCallback? onTap,
      required int index}) {
    // TODO: implement createSpecialText
    throw UnimplementedError();
  }
}


在这段代码中,如果文本包含一个@符号,那么我们将使用该数据创建一个Chip,否则,我们将添加实际文本。
使用创建的MySpecialTextSpanBuilder类:
Scaffold(
          backgroundColor: Colors.blue,
          body: ExtendedTextField(
            style: TextStyle(color: Colors.red),
            decoration: InputDecoration(
              border: OutlineInputBorder(),
            ),
            specialTextSpanBuilder: MySpecialTextSpanBuilder(),
          ),
        )

完整的可运行代码片段:
import 'package:extended_text_field/extended_text_field.dart';
import 'package:flutter/material.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        dividerColor: Colors.green,
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: SafeArea(
        child: Scaffold(
          backgroundColor: Colors.blue,
          body: ExtendedTextField(
            cursorColor: Colors.black,
            style: TextStyle(color: Colors.red),
            decoration: InputDecoration(
              border: OutlineInputBorder(),
            ),
            specialTextSpanBuilder: MySpecialTextSpanBuilder(),
          ),
        ),
      ),
    );
  }
}

class MySpecialTextSpanBuilder extends SpecialTextSpanBuilder {
  @override
  TextSpan build(String data,
      {TextStyle? textStyle, SpecialTextGestureTapCallback? onTap}) {
    final lookingFor = "@";
    final splitData = data.split(" ");
    final spans = splitData.map((e) {
      if (e == lookingFor) {
        return WidgetSpan(
          child: Chip(
            label: Text(e),
          ),
        );
      } else {
        return TextSpan(
          text: e,
          style: TextStyle(color: Colors.red),
        );
      }
    }).toList();
    return TextSpan(children: spans, style: textStyle);
  }

  @override
  SpecialText? createSpecialText(String flag,
      {TextStyle? textStyle,
      SpecialTextGestureTapCallback? onTap,
      required int index}) {
    // TODO: implement createSpecialText
    throw UnimplementedError();
  }
}

使用

您可以使用RichText作为子元素和WidgetSpan一起使用:

一个不可变的小部件,嵌入文本中。

结果

enter image description here

代码

RichText(
      text: TextSpan(
        children: [
          TextSpan(
            text: "one",
          ),
          WidgetSpan(
            child: Chip(
              label: Text("two"),
            ),
          ),
          TextSpan(
            text: "three",
          ),
        ],
      ),
    )

但是如何在TextField或TextFormField中实现呢? - user3808307
@user3808307 它需要在TextField的中间吗?还是可以在textField的开头或结尾? - MendelG
1
谢谢!我会在19小时内授予奖金。我不能更早,非常感谢!!! - user3808307
1
@user3808307 为 MySpecialTextSpanBuilder 创建一个构造函数,并传入你要查找的内容。 - MendelG
1
@user3808307 另外,您可能想在示例中尝试使用split(" ")方法,以便根据完整单词或包含某个单词来进行拆分。 - MendelG
显示剩余7条评论

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