flutter 中的单个 TextField 可以具有可变行高吗?

Can a single TextField in flutter have variable line height?

我正在实现一个简单的富文本编辑器,该编辑器使用识别基本 Markdown 语法的文本编辑控制器呈现文本,我将 link 下面的一些代码。

一切正常,我遇到的唯一问题是当文本样式需要更大的行高时,例如 # h1 应该呈现为标题,因此需要更大的行高重叠上一行,如下面的屏幕截图所示。

到目前为止,我无法根据所显示文本的样式在 TextView 变量中设置行高,在 Flutter TextView 中甚至可以实现吗?

这是我的文本编辑控制器的片段和详细说明我的问题的屏幕截图。

import 'dart:ui';

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

class AddNotePage extends StatelessWidget {
  final TextEditingController _controller = MarkdownTextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add Note'),
      ),
      body: GestureDetector(
        onVerticalDragDown: (_) {
          FocusScopeNode currentFocus = FocusScope.of(context);

          if (!currentFocus.hasPrimaryFocus) {
            currentFocus.unfocus();
          }
        },
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Expanded(
              child: TextField(
                style: defaultTextStyle,
                controller: _controller,
                decoration: InputDecoration(
                  hintText: "Insert your message",
                  border: UnderlineInputBorder(
                    borderSide: BorderSide.none,
                  ),
                ),
                scrollPadding: EdgeInsets.all(20.0),
                keyboardType: TextInputType.multiline,
                maxLines: null,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

const Map<String, TextStyle> defaultMarkdownStyleMap = {
  r'^# .*?$': TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 50,
  ),
  r'^## .*?$': TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 40,
  ),
  r'^### .*?$': TextStyle(
    fontWeight: FontWeight.bold,
    fontSize: 30,
  ),
  r'__(.*?)\__': TextStyle(fontStyle: FontStyle.italic, fontSize: 20),
  r'~~(.*?)~~': TextStyle(decoration: TextDecoration.lineThrough, fontSize: 20),
  r'\*\*(.*?)\*\*': TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
};

const TextStyle defaultTextStyle = TextStyle(fontSize: 20);

class MarkdownTextEditingController extends TextEditingController {
  final Map<String, TextStyle> styleMap;
  final Pattern pattern;

  MarkdownTextEditingController({this.styleMap = defaultMarkdownStyleMap})
      : pattern = RegExp(
            styleMap.keys.map((key) {
              return key;
            }).join('|'),
            multiLine: true);

  @override
  TextSpan buildTextSpan(
      {required BuildContext context,
      TextStyle? style,
      required bool withComposing}) {
    final List<InlineSpan> children = [];

    text.splitMapJoin(
      pattern,
      onMatch: (Match match) {
        TextStyle? markdownStyle = styleMap[styleMap.keys.firstWhere(
          (e) {
            return RegExp(e).hasMatch(match[0]!);
          },
        )];

        children.add(TextSpan(
          text: match[0],
          style: style!.merge(markdownStyle),
        ));
        return "";
      },
      onNonMatch: (String text) {
        children
            .add(TextSpan(text: text, style: style!.merge(defaultTextStyle)));
        return "";
      },
    );

    return TextSpan(style: style, children: children);
  }
}

我找到了解决办法。 我需要做的就是使用 TextField 的 strutStyle 属性。

如文档所述:

The strut style used for the vertical layout.

StrutStyle is used to establish a predictable vertical layout. Since fonts may vary depending on user input and due to font fallback, StrutStyle.forceStrutHeight is enabled by default to lock all lines to the height of the base TextStyle, provided by style. This ensures the typed text fits within the allotted space.