flutter 中间组件自适应宽度

发布于:2025-09-08 ⋅ 阅读:(16) ⋅ 点赞:(0)

使用Flexible + IntrinsicWidth

Row(
  children: [
    Text('第一个text'),
    IntrinsicWidth(
        child: ConstrainedBox(
          constraints: BoxConstraints(maxWidth: 200), // 最大宽度限制
          child: Text(
            '中间的text可能很长也可能很短',
            overflow: TextOverflow.ellipsis,
            maxLines: 1,
          ),
        ),
    ),
    Text('第三个text'),
  ],
)

使用LayoutBuilder + 自定义计算

LayoutBuilder(
  builder: (context, constraints) {
    final firstText = '第一个text';
    final middleText = '中间的text可能很长也可能很短';
    final thirdText = '第三个text';
    
    // 计算文本宽度
    final textPainter = TextPainter(
      text: TextSpan(text: middleText),
      textDirection: TextDirection.ltr,
    );
    textPainter.layout();
    
    final middleTextWidth = textPainter.width;
    final maxWidth = 200.0;
    
    // 使用实际宽度或最大宽度中的较小值
    final actualWidth = middleTextWidth < maxWidth ? middleTextWidth : maxWidth;
    
    return Row(
      children: [
        Text(firstText),
        SizedBox(
          width: actualWidth,
          child: Text(
            middleText,
            overflow: TextOverflow.ellipsis,
            maxLines: 1,
          ),
        ),
        Text(thirdText),
      ],
    );
  },
)

使用CustomMultiChildLayout

CustomMultiChildLayout(
  delegate: _ThreeTextLayoutDelegate(maxWidth: 200),
  children: [
    LayoutId(
      id: 'first',
      child: Text('第一个text'),
    ),
    LayoutId(
      id: 'middle',
      child: Text(
        '中间的text可能很长也可能很短',
        overflow: TextOverflow.ellipsis,
        maxLines: 1,
      ),
    ),
    LayoutId(
      id: 'third',
      child: Text('第三个text'),
    ),
  ],
)

class _ThreeTextLayoutDelegate extends MultiChildLayoutDelegate {
  final double maxWidth;
  
  _ThreeTextLayoutDelegate({required this.maxWidth});
  
  @override
  void performLayout(Size size) {
    // 获取第一个text的尺寸
    final firstSize = layoutChild('first', BoxConstraints.loose(size));
    
    // 获取第三个text的尺寸
    final thirdSize = layoutChild('third', BoxConstraints.loose(size));
    
    // 计算中间text可用的最大宽度
    final availableWidth = size.width - firstSize.width - thirdSize.width;
    
    // 计算中间text的实际宽度(不超过maxWidth)
    final middleConstraints = BoxConstraints(
      maxWidth: availableWidth.clamp(0, maxWidth),
      minWidth: 0,
    );
    final middleSize = layoutChild('middle', middleConstraints);
    
    // 布局
    positionChild('first', Offset.zero);
    positionChild('middle', Offset(firstSize.width, 0));
    positionChild('third', Offset(firstSize.width + middleSize.width, 0));
  }

  @override
  bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => false;
}

使用StatefulWidget + 动态计算

class AdaptiveTextRow extends StatefulWidget {
  final String firstText;
  final String middleText;
  final String thirdText;
  final double maxMiddleWidth;
  
  const AdaptiveTextRow({
    super.key,
    required this.firstText,
    required this.middleText,
    required this.thirdText,
    this.maxMiddleWidth = 200,
  });

  @override
  State<AdaptiveTextRow> createState() => _AdaptiveTextRowState();
}

class _AdaptiveTextRowState extends State<AdaptiveTextRow> {
  double? middleTextWidth;
  
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _calculateMiddleTextWidth();
    });
  }
  
  void _calculateMiddleTextWidth() {
    final textPainter = TextPainter(
      text: TextSpan(text: widget.middleText),
      textDirection: TextDirection.ltr,
    );
    textPainter.layout();
    
    setState(() {
      middleTextWidth = textPainter.width;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    if (middleTextWidth == null) {
      return Row(
        children: [
          Text(widget.firstText),
          Flexible(
            child: Text(
              widget.middleText,
              overflow: TextOverflow.ellipsis,
              maxLines: 1,
            ),
          ),
          Text(widget.thirdText),
        ],
      );
    }
    
    final actualWidth = middleTextWidth! < widget.maxMiddleWidth 
        ? middleTextWidth! 
        : widget.maxMiddleWidth;
    
    return Row(
      children: [
        Text(widget.firstText),
        SizedBox(
          width: actualWidth,
          child: Text(
            widget.middleText,
            overflow: TextOverflow.ellipsis,
            maxLines: 1,
          ),
        ),
        Text(widget.thirdText),
      ],
    );
  }
}

// 使用方式
AdaptiveTextRow(
  firstText: '第一个text',
  middleText: '中间的text可能很长也可能很短',
  thirdText: '第三个text',
  maxMiddleWidth: 200,
)

网站公告

今日签到

点亮在社区的每一天
去签到