将容器对齐到文本的顶部和底部

时间:2019-02-13 07:29:00

标签: flutter flutter-layout

我正在尝试在两个“文本”小部件的左侧对齐一个彩色矩形。具体来说,我希望彩色矩形的底部与下部Text的基线对齐,而矩形的顶部与上部Text的字体高度对齐。这是我要达到的目标的模拟:Screenshot of desired layout 到目前为止,我的代码:

final TextStyle helloTextStyle = const TextStyle(
  fontWeight: FontWeight.w600,
  fontSize: 28,
  letterSpacing: 0,
  wordSpacing: 0,
  fontFamily: "DejaVuSansCondensed",
  color: Color(0XFF232444),
  decoration: TextDecoration.none,
);
final TextStyle everyoneTextStyle = const TextStyle(
  fontWeight: FontWeight.w700,
  fontSize: 38,
  letterSpacing: 0,
  fontFamily: "DejaVuSansCondensed",
  color: Color(0XFF232444),
  decoration: TextDecoration.none,
);

return Row(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Container(
      decoration: BoxDecoration(
        border: Border(
          left: BorderSide(
              width: 16.0,
              color: Colors.red),
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text("HELLO", style: helloTextStyle),
          Text("EVERYONE", style: everyoneTextStyle),
        ],
      ),
    ),
  ],
)

我该如何将彩色矩形的底部与下部文本的基线对齐,并将矩形的顶部与上部文本的字体高度对齐?

编辑:一种解决方案是确定基线和“文本”小部件的底部之间的距离以及顶盖高度和“文本”小部件的顶部之间的距离。文本小部件似乎没有提供这些值。

3 个答案:

答案 0 :(得分:0)

Row包装在Container中,并定义其height属性:

 Container(
  height: MediaQuery.of(context).size.height/4 ,
  child: Row(
    children: <Widget>[
      Column(
       children: <Widget>[
          Container(
           width: 16.0,
           color: Colors.red,
          ),
        ]
      ),
      Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Text("HELLO", style: helloTextStyle),
          Text("EVERYONE", style: everyoneTextStyle),
        ]
      ),
    ]
  ),
 ),

答案 1 :(得分:0)

您不需要像以前一样将Column用作Container的子代。这样,它就不会以文本为基准。

一种方法:

double fontSize1 = 38.0;
double fontSize2 = 28.0;

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: IntrinsicHeight(
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Padding(
                padding: EdgeInsets.only(top:(fontSize2 / 4.5),bottom: (fontSize1 / 4.2)),
                child: Container(
                  decoration: BoxDecoration(
                    border: Border(
                      left: BorderSide(
                          width: 16.0,
                          color: Colors.red),
                    ),
                  ),
                ),
              ),
              Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text("HELLO", style: helloTextStyle),
                  Text("EVERYONE", style: everyoneTextStyle),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

输出:

enter image description here

具有:

  double fontSize1 = 68.0;
  double fontSize2 = 18.0;

输出: enter image description here

因此填充是立即自动计算的。

答案 2 :(得分:0)

没有Flutter API可以获取文本的确切边界。 Flutter: finding the exact bounds of text涵盖了这一点。就是说,我有一个基于相同讨论的解决方案。

方法是在画布上绘制一个字符(在我的情况下为大写“ I”),然后扫描图像像素以查找字符的边缘。我计算字符和图像边缘之间的像素行,并使用它来设置彩色块上的填充。我的解决方案更加复杂,因为我在一个列中有两个Text小部件,每个Text的大小都不同。

注意:除非您真正关心与字符边缘的精确对齐,否则我不会建议这种解决方案。

布局代码:

IntrinsicHeight(
  child: Row(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: <Widget>[
      FutureBuilder<TopBottomPadding>(
          future: _calcPadding(
              TextSpan(
                  text: "I", style: helloTextStyle),
              TextSpan(
                  text: "I", style: everyoneTextStyle),
              mediaQueryData.textScaleFactor),
          builder: (BuildContext context, tuple) {
            return Padding(
              padding: EdgeInsets.only(
                top: tuple.data.top,
                bottom: tuple.data.bottom,
              ),
              child: Container(
                decoration: BoxDecoration(
                  border: Border(
                    left: BorderSide(
                        width: 16.0, color: Colors.red),
                  ),
                ),
              ),
            );
          }),
      Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text("HELLO", style: helloTextStyle),
          Text("EVERYONE", style: everyoneTextStyle),
        ],
      ),
    ],
  ),
)

生成图像涉及异步调用,因此我已经注册了FutureBuilder小部件。

Future<TopBottomPadding> _calcPadding(final TextSpan topSpan,
    final TextSpan bottomSpan, final double textScaleFactor) async {
  final topPadding = await _calcTopPadding(topSpan, textScaleFactor);
  final bottomPadding = await _calcBottomPadding(bottomSpan, textScaleFactor);
  return TopBottomPadding(topPadding, bottomPadding);
}

Future<double> _calcTopPadding(TextSpan span, double textScaleFactor) async {
  final int bytesPerPixel = 4;
  final imageData =
      await _getImageByteData(span, ImageByteFormat.rawRgba, textScaleFactor);
  final Size imageSize = imageData.size;
  final ByteData byteData = imageData.byteData;
  final numRows =
      (byteData.lengthInBytes / (bytesPerPixel * imageSize.width)).round();
  int foundRow;
  /// Scan each pixel from top to bottom keeping track of the row
  for (int row = 0; row < numRows && foundRow == null; row++) {
    final int rowLength = bytesPerPixel * imageSize.width.round();
    final int startRowByteIndex = row * rowLength;
    /// Only looking at first byte of each pixel is good enough
    for (int byteArrayIndex = startRowByteIndex;
        byteArrayIndex < row * rowLength + rowLength;
        byteArrayIndex += bytesPerPixel) { 
      final int byteValue = byteData.getUint8(byteArrayIndex);
      /// The background is white so look for a non-white pixel.
      if (foundRow == null && byteValue != 0xff) {
        foundRow = row;
        break;
      }
    }
  }
  final double result = foundRow == null ? 0 : foundRow.toDouble();
  return result;
}

Future<double> _calcBottomPadding(
    final TextSpan span, final textScaleFactor) async {
  final int bytesPerPixel = 4;
  final imageData =
      await _getImageByteData(span, ImageByteFormat.rawRgba, textScaleFactor);
  final Size imageSize = imageData.size;
  final ByteData byteData = imageData.byteData;
  final numRows =
      (byteData.lengthInBytes / (bytesPerPixel * imageSize.width)).round();
  int foundRow;
  /// Scan each pixel from bottom to top keeping track of the row
  for (int row = numRows - 1; row >= 0 && foundRow == null; row--) {
    final int rowLength = bytesPerPixel * imageSize.width.round();
    final int startRowByteIndex = row * rowLength;
    /// Only looking at first byte of each pixel is good enough
    for (int byteArrayIndex = startRowByteIndex;
        byteArrayIndex < row * rowLength + rowLength;
        byteArrayIndex += bytesPerPixel) {
      final int byteValue = byteData.getUint8(byteArrayIndex);
      /// The background is white so look for a non-white pixel.
      if (foundRow == null && byteValue != 0xff) {
        foundRow = row;
        break;
      }
    }
  }
  final double foundRowIndex = foundRow == null ? 0 : foundRow.toDouble();
  final int heightAsZeroBasedIndex = imageSize.height.round() - 1;
  final double paddingValue = heightAsZeroBasedIndex - foundRowIndex;
  return paddingValue;
}

Future<ImageData> _getImageByteData(final TextSpan span,
    final ImageByteFormat byteFormat, final double textScaleFactor) async {
  final painter = TextPainter(
      text: span,
      textDirection: TextDirection.ltr,
      textScaleFactor: textScaleFactor);
  painter.layout();
  final imageData = ImageData();
  imageData.size = Size(painter.width, painter.height);
  final recorder = PictureRecorder();
  final screen = Offset.zero & imageData.size;
  final canvas = Canvas(recorder);
  drawBackground(canvas, screen);
  painter.paint(canvas, Offset.zero);
  final picture = recorder.endRecording();
  final image =
      await picture.toImage(screen.width.round(), screen.height.round());
  final ByteData byteData = await image.toByteData(format: byteFormat);
  imageData.byteData = byteData;
  return imageData;
}

void drawBackground(final Canvas canvas, final Rect screen) {
  canvas.drawRect(
      screen,
      Paint()
        ..color = Colors.white
        ..style = PaintingStyle.fill);
}

class TopBottomPadding {
  double top;
  double bottom;

  TopBottomPadding(this.top, this.bottom);
}

class ImageData {
  ByteData byteData;
  Size size;
}

此解决方案适用于任何屏幕密度,字体大小或文本比例因子。