You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ListView中Text组件高度无法自适应内容,如何实现高度随内容调整?

Flutter ListView内Text组件高度无法自动包裹内容的解决方案

你的问题主要来自两个关键点:

  1. Text组件默认不会自动换行,长文本会被截断,导致高度无法跟随内容扩展
  2. ListView.builder使用了prototypeItem参数,它会强制所有列表项使用原型项的固定高度,即使内容更多也无法撑开

解决步骤:

  • 给所有需要自适应高度的Text组件添加softWrap: true和maxLines: null,允许文本自动换行并占据足够高度
  • 移除ListView.builder的prototypeItem参数,让每个列表项根据自身内容计算高度(如果追求性能,也可以用itemExtent但不推荐,因为无法适配动态内容)

修改后的关键代码片段:

1. 调整MaterialPriceListItem中的Text组件:

// 标签文本部分
Text(
  label,
  style: const TextStyle(fontSize: 22),
  softWrap: true,
  maxLines: null,
)

// 价格文本部分
Text(
  "${moneyFormat(price)} \$",
  style: TextStyle(color: getColor(priceDiff), fontSize: 18),
  softWrap: true,
  maxLines: null,
)

// 价格变动文本部分
Text(
  getPriceChangeText(priceDiff),
  style: TextStyle(color: getColor(priceDiff), fontSize: 14),
  softWrap: true,
  maxLines: null,
)

2. 修改ListView.builder移除prototypeItem:

ListView.builder(
  itemCount: a.length,
  // 移除prototypeItem参数
  itemBuilder: (context, index) {
    return MaterialPriceListItem(
      label: a[index].label,
      price: a[index].price,
      priceDiff: a[index].priceDiff,
    );
  },
)

完整修改后的代码:

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';

void main() {
  runApp(const MyApp());
}

class MaterialData {
  final String label;
  final double price;
  final double priceDiff;

  MaterialData(this.label, this.price, this.priceDiff);
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ตลาดหลักทรัพย์',
      theme: ThemeData(primarySwatch: Colors.indigo),
      home: const MyHomePage(title: 'ตลาดหลักทรัพย์'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<MaterialData> data = [
    MaterialData('ไม้กระดาน', 48, 0),
    MaterialData('วิญญาณร้าย', 39, 1),
    MaterialData('ตุ๊กตาหิมะ', 31, 0),
    MaterialData('ทองคำ', 609000000000, 1),
    MaterialData('ไข่เอเลียน', 31, 0),
    MaterialData('ทับทิม', 582, -18),
    MaterialData('ล็อบสเตอร์ทอง', 2500, 0),
    MaterialData('เหล็ก', 43000, 5000),
    MaterialData('น้ำมันกลั่น', 43, 0),
    MaterialData('ไก่ในถาด', 34, 1),
  ];

  List<MaterialData> a = List<MaterialData>.empty();

  @override
  void initState() {
    a = List<MaterialData>.generate(10000, (i) => data[i % 10]);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.builder(
        itemCount: a.length,
        itemBuilder: (context, index) {
          return MaterialPriceListItem(
            label: a[index].label,
            price: a[index].price,
            priceDiff: a[index].priceDiff,
          );
        },
      ),
    );
  }
}

class MaterialPriceListItem extends StatelessWidget {
  final String label;
  final double price;
  final double priceDiff;

  const MaterialPriceListItem({
    Key? key,
    required this.label,
    required this.price,
    required this.priceDiff,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.fromLTRB(8, 13.0, 8, 13.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center, // 确保行内元素垂直居中
        children: [
          getIcon(priceDiff),
          Expanded(
            flex: 7,
            child: Container(
              padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 0),
              alignment: Alignment.centerLeft,
              child: Text(
                label,
                style: const TextStyle(fontSize: 22),
                softWrap: true,
                maxLines: null,
              ),
            ),
          ),
          Expanded(
            flex: 2,
            child: Container(
              padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 0),
              alignment: Alignment.center,
              child: Text(
                "${moneyFormat(price)} \$",
                style: TextStyle(color: getColor(priceDiff), fontSize: 18),
                softWrap: true,
                maxLines: null,
              ),
            ),
          ),
          Expanded(
            flex: 1,
            child: Container(
              padding: const EdgeInsets.fromLTRB(8.0, 0, 0, 0),
              alignment: Alignment.center,
              child: Text(
                getPriceChangeText(priceDiff),
                style: TextStyle(color: getColor(priceDiff), fontSize: 14),
                softWrap: true,
                maxLines: null,
              ),
            ),
          ),
        ],
      ),
    );
  }

  String moneyFormat(double value) {
    var nf = NumberFormat("##,###.##", "en_US");
    return nf.format(value);
  }

  String getPriceChangeText(double priceChange) {
    if (priceChange.sign > 0) {
      return "+${moneyFormat(priceChange.abs())}";
    } else if (priceChange.sign < 0) {
      return "-${moneyFormat(priceChange.abs())}";
    } else {
      return moneyFormat(priceChange);
    }
  }

  Widget getIcon(double priceChange) {
    if (priceChange < 0) {
      return FaIcon(
        FontAwesomeIcons.arrowDown,
        color: getColor(priceChange),
        size: 18,
      );
    } else if (priceChange > 0) {
      return FaIcon(
        FontAwesomeIcons.arrowUp,
        color: getColor(priceChange),
        size: 18,
      );
    } else {
      return Center(
        child: FaIcon(
          FontAwesomeIcons.arrowRight,
          color: getColor(priceChange),
          size: 18,
        ),
      );
    }
  }

  Color getColor(double priceChange) {
    if (priceChange < 0) {
      return const Color.fromARGB(255, 198, 40, 40);
    } else if (priceChange > 0) {
      return const Color.fromARGB(255, 46, 125, 50);
    } else {
      return const Color.fromARGB(255, 21, 101, 192);
    }
  }
}

内容的提问来源于stack exchange,提问作者Jongz Puangput

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:05:22