Flutter¥和数字价格不能居底对齐。去掉Flutter文字空白区域

最近有ui走查反馈价格¥和数字没有底部对,所以对flutter的文字绘制做了下了解,以此解决ui一直以来纠结的历史问题。
先看看正常情况和非正常情况的ui展示样式吧
在这里插入图片描述

可以看到数字,汉字和字母(不同的字母所占的高度还不一致) 24呵呵jki这文字
再给出字符的显示规则
在这里插入图片描述

针对价格(数字类型的展示) 其实获取的应该是Capheight,所以在Flutter中需要根据
TextPainter 来获取相关信息
Capheight = BaseLineHeight - o(字符空白区域到顶部距离),但Capheight距离顶部的距离无法获取,所以需要采取别的方式来。
贴出关键代码

TextPainter textPainter = TextPainter()
List<LineMetrics> list = textPainter.computeLineMetrics();
if (list?.isNotEmpty ?? false) {
// baseLine高度
toBaseLineHeight = list[0].ascent;
// 顶部空白距离
ascDistance = toBaseLineHeight - list[0].unscaledAscent;
} else {
  toBaseLineHeight = textPainter.computeDistanceToActualBaseline(TextBaseline.alphabetic);
  ascDistance = 0;
}
Size size = textPainter.size;
// 需要偏移的距离
bottomDistance = size.height - toBaseLineHeight;
// 存入次fontSize对应的数据 防止下次再计算提升性能
if (fontSizeInfo == null) {
  fontSizeMap[textStyle.fontSize] = FontSizeInfo(toBaseLineHeight, bottomDistance, ascDistance);
}
capheight = toBaseLineHeight - ascDistance - bottomDistance + 1 // 加1是防止小数,且1像素影响不大

稍后会合进develop分支
使用示例

Container(
  color: Colors.amber,
  margin: EdgeInsets.only(top: 6,bottom: 6),
  child: ExPrice('123456', TextStyle(fontSize: 50,height: 1.0),leftPriceUnit: '¥',leftPriceUnitStyle: TextStyle(fontSize: 12),),
),

完整代码如下

import 'dart:ui';

import 'package:flutter/material.dart';

/// 价格展示模块 修正控件底部有间距 导致不居中的问题 主要针对 ¥1234这种情况 不针对汉字 但如果需要可以借鉴此写法
class ExPrice extends StatelessWidget {
final String price; // 价格字符串
final TextStyle textStyle; // 价格Style
final String leftPriceUnit; // 价格前面的符号
final TextStyle leftPriceUnitStyle; // 左边价格符号样式
static Map<double, FontSizeInfo> fontSizeMap = {}; // 不同字号对应的distance 防止多次计算 提升性能

ExPrice(this.price, this.textStyle, {this.leftPriceUnit = '¥', this.leftPriceUnitStyle}) : assert(price != null);

@override
Widget build(BuildContext context) {
    print('${DateTime.now()}');
FontSizeInfo fontSizeInfo = fontSizeMap[textStyle.fontSize];
FontSizeInfo priceUnitSizeInfo = fontSizeMap[leftPriceUnitStyle.fontSize];

double toBaseLineHeight; // 价格的基准线高度
double bottomDistance; // 价格基准线距离文字底部空白区域的高度
double ascDistance; // 控件顶部距离文字顶部空白区域高度
double priceUnitHeight; // 价格的文字高度
double priceUnitWidth; // 文字宽度

    // 价格内容区域
TextPainter textPainter = TextPainter(
        text: TextSpan(
          text: price,
style: textStyle,
),
textDirection: TextDirection.ltr,
strutStyle: StrutStyle.fromTextStyle(textStyle, height: 1, forceStrutHeight: true),
locale: Localizations.localeOf(context, nullOk: true),
maxLines: 1,
textHeightBehavior: TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: false))
      ..layout(maxWidth: double.infinity, minWidth: 0);
    if (fontSizeInfo != null) {
// baseLine高度
toBaseLineHeight = fontSizeInfo.toBaseLineHeight;
// 字符底部空白高度,绘制时需要偏移这个距离
bottomDistance = fontSizeInfo.bottomDistance;
// 顶部空白距离
ascDistance = fontSizeInfo.ascDistance;
} else {
      List<LineMetrics> list = textPainter.computeLineMetrics();
      if (list?.isNotEmpty ?? false) {
// baseLine高度
toBaseLineHeight = list[0].ascent;
// 顶部空白距离
ascDistance = toBaseLineHeight - list[0].unscaledAscent;
} else {
        toBaseLineHeight = textPainter.computeDistanceToActualBaseline(TextBaseline.alphabetic);
ascDistance = 0;
}
    }
    Size size = textPainter.size;
// 需要偏移的距离
bottomDistance = size.height - toBaseLineHeight;
// 存入次fontSize对应的数据 防止下次再计算提升性能
if (fontSizeInfo == null) {
fontSizeMap[textStyle.fontSize] = FontSizeInfo(toBaseLineHeight, bottomDistance, ascDistance);
}

// 价格符号相关
if (priceUnitSizeInfo == null) {
      TextPainter priceUnitPainter = getTextPainter(context, leftPriceUnit, leftPriceUnitStyle);
priceUnitWidth = priceUnitPainter.width;
List<LineMetrics> list = priceUnitPainter.computeLineMetrics();
      if (list?.isNotEmpty ?? false) {
        double priceToBaseLineHeight = list[0].ascent;
double priceAscDistance = priceToBaseLineHeight - list[0].unscaledAscent;
priceUnitHeight = priceToBaseLineHeight - priceAscDistance + 1;
} else {
        priceUnitHeight = priceUnitPainter.computeDistanceToActualBaseline(TextBaseline.alphabetic);
ascDistance = 0;
}
fontSizeMap[leftPriceUnitStyle.fontSize] = FontSizeInfo(priceUnitHeight, 0, 0)
        ..width = (priceUnitPainter.size?.width ?? 0);
} else {
      priceUnitHeight = priceUnitSizeInfo.toBaseLineHeight;
priceUnitWidth = priceUnitSizeInfo.width;
}

    print('${DateTime.now()}');
    return CustomPaint(
      painter: ExPricePainter(context, price, leftPriceUnit, textStyle, leftPriceUnitStyle, bottomDistance,
priceUnitHeight, priceUnitWidth),
// 文字高度应该是到基准线高度
size: Size(size.width + 10, toBaseLineHeight - ascDistance - bottomDistance + 1),
);
}
}

class ExPricePainter extends CustomPainter {
// 价格字符串
final String price;
  final String priceUnitText; // 价格符号
final TextStyle textStyle;
  final TextStyle priceStyle;
  final BuildContext context;
  final double distance;
  final double priceUnitHeight; // 价格的文字高度
final double priceUnitWidth; // 价格文字宽度

ExPricePainter(this.context, this.price, this.priceUnitText, this.textStyle, this.priceStyle, this.distance,
      this.priceUnitHeight, this.priceUnitWidth);

@override
void paint(Canvas canvas, Size size) {
    print('ExPricePainter size: ${size.height}');
print('nowtime:${DateTime.now()}');
TextPainter textPainter = TextPainter(
        text: TextSpan(text: price, style: textStyle),
textDirection: TextDirection.ltr,
locale: Localizations.localeOf(context, nullOk: true),
maxLines: 1,
textHeightBehavior: TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: false));
textPainter..layout(maxWidth: double.infinity, minWidth: 0);
textPainter.paint(canvas, Offset(priceUnitWidth ?? 0, -distance));
TextPainter priceUnit = TextPainter(
      text: TextSpan(
        text: priceUnitText,
style: priceStyle,
),
textDirection: TextDirection.ltr,
);
priceUnit
      ..layout(maxWidth: double.infinity, minWidth: 0)
      ..paint(canvas, Offset(0, size.height - priceUnitHeight));
print('nowtime:${DateTime.now()}');
}

@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}

/// 获取文本的宽度和高度
TextPainter getTextPainter(BuildContext context, String text, TextStyle textStyle) {
  TextPainter textPainter = TextPainter(
      text: TextSpan(
        text: text,
style: textStyle,
),
textDirection: TextDirection.ltr,
strutStyle: StrutStyle.fromTextStyle(textStyle, height: 1, forceStrutHeight: true),
locale: Localizations.localeOf(context, nullOk: true),
maxLines: 1,
textHeightBehavior: TextHeightBehavior(applyHeightToFirstAscent: false, applyHeightToLastDescent: false))
    ..layout(maxWidth: double.infinity, minWidth: 0);
  return textPainter;
}

/// 不同文字对应的偏移信息
class FontSizeInfo {
  double toBaseLineHeight; // 顶部到baseLine的高度
double bottomDistance; // baseLine距离底部的空白距离
double ascDistance; // 文字距离顶部的空白距离
double width; // 文字宽度

FontSizeInfo(this.toBaseLineHeight, this.bottomDistance, this.ascDistance); // 数字底部的空白高度

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值