如何在 Flutter 中更改文本字段选择颜色

问题描述 投票:0回答:1

我想在 Flutter 中创建一个文本字段,当我选择文本的一部分并按下按钮时,只有选定的部分会更改其颜色,例如更改为红色。此外,如果选择文本的另一部分并且其颜色发生变化,则应保留先前文本的样式。

我的目标是修改 Flutter 中文本字段内文本不同部分的颜色。我应该采取哪些步骤来实现这一目标?

flutter dart select colors textfield
1个回答
0
投票

我相信最好的方法是使用

SelectableText.rich()
。这不允许您像
TextField
那样编辑文本,因此您要么需要自己实现编辑文本,要么找到一种巧妙的方法在
Stack
中显示它们。

这是一个可以完成您所描述的工作的 Flutter 应用程序:

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) => const MaterialApp(home: MyHomePage());
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const _text = 'Lorem ipsum dolor sit amet, '
      'consectetur adipiscing elit, '
      'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. '
      'Ut enim ad minim veniam, '
      'quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. '
      'Duis aute irure dolor in reprehenderit '
      'in voluptate velit esse cillum dolore eu fugiat nulla pariatur. '
      'Excepteur sint occaecat cupidatat non proident, '
      'sunt in culpa qui officia deserunt mollit anim id est laborum.';
  final List<TextStyle> _style = List.filled(_text.length, const TextStyle());
  (int startIndex, int endIndex) _selection = (0, 0);

  Widget get highlightedText {
    final List<TextSpan> children = [];
    String currentText = '';
    late TextStyle currentStyle;

    for (int i = 0; i < _text.length; i++) {
      if (currentText.isEmpty) {
        currentText = _text[i];
        currentStyle = _style[i];
      } else {
        currentText += _text[i];
        if (i + 1 == _text.length || _style[i + 1] != currentStyle) {
          children.add(TextSpan(text: currentText, style: currentStyle));
          currentText = '';
        }
      }
    }

    return SelectableText.rich(
      TextSpan(children: children),
      onSelectionChanged: (selection, cause) {
        final (base, extent) = (selection.baseOffset, selection.extentOffset);
        _selection = (min(base, extent), max(base, extent));
      },
    );
  }

  void hilight(Color color) {
    final (start, end) = _selection;
    if (start == end) return;

    final style = TextStyle(
        color: color.computeLuminance() > 0.25 ? Colors.black : Colors.white,
        backgroundColor: color);
    for (int i = start; i < end; i++) {
      setState(() => _style[i] = style);
    }
  }

  late final Widget highlightButtons = Padding(
    padding: const EdgeInsets.only(top: 50, bottom: 25),
    child: Row(children: [
      for (final color in [
        Colors.red,
        Colors.orange,
        Colors.amber,
        Colors.yellow,
        Colors.lime,
        Colors.green,
        Colors.cyan,
        Colors.blue,
        Colors.indigo,
        Colors.purple,
      ])
        _HighlightButton(color: color, onPressed: () => hilight(color))
    ]),
  );

  late final Widget resetButton = OutlinedButton(
    style: OutlinedButton.styleFrom(foregroundColor: Colors.grey),
    onPressed: () {
      _selection = (0, _text.length);
      hilight(const Color(0x00FFFFFF));
    },
    child: const Text('reset'),
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        margin: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width / 16),
        alignment: Alignment.center,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            highlightedText,
            highlightButtons,
            resetButton,
          ],
        ),
      ),
    );
  }
}

class _HighlightButton extends StatelessWidget {
  const _HighlightButton({required this.color, required this.onPressed});
  final Color color;
  final void Function() onPressed;

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Padding(
        padding: const EdgeInsets.all(4),
        child: ElevatedButton(
          style: OutlinedButton.styleFrom(backgroundColor: color),
          onPressed: onPressed,
          child: const SizedBox.shrink(),
        ),
      ),
    );
  }
}

这是在行动:

© www.soinside.com 2019 - 2024. All rights reserved.