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

Flutter中如何实现适配全机型、位于ListView.builder内的等宽高正方形容器

问题根因
  • 你使用全局屏幕宽度MediaQuery.of(context).size.width计算Item宽度,当组件父级存在边距、或未占满全屏时,计算出的宽度和实际ListView可用宽度不匹配,会导致正方形比例失效
  • 横向ListView的Item只指定了宽度没有限制高度,当外层AspectRatio(2.8/1)的高度约束较小时,Column会挤压内部正方形区域的高度,AspectRatio会优先服从父级的紧约束,无法保持1:1比例
解决方案

修改后的完整代码如下:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor:Colors.black,
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 2.8 / 1,
      child: LayoutBuilder(
        // 用LayoutBuilder拿当前ListView的可用宽度,避免全局宽度的误差
        builder: (context, constraints) {
          // 单个Item的宽度 = 可用宽度的30%,减去右侧5的padding
          final itemWidth = constraints.maxWidth * 0.3 - 5;
          return ListView.builder(
            scrollDirection: Axis.horizontal,
            shrinkWrap: true,
            itemCount: 3,
            itemBuilder: (BuildContext context, int index) {
              return SizedBox(
                width: itemWidth,
                // 强制Item高度和宽度匹配,保证内部正方形不会被挤压
                height: itemWidth,
                child: GestureDetector(
                  child: Padding(
                    padding: const EdgeInsets.only(right: 5.0),
                    child: Card(
                      elevation: 0,
                      child: Column(
                        children: [
                          ClipRRect(
                            borderRadius: BorderRadius.only(
                              topLeft: Radius.circular(5),
                              topRight: Radius.circular(5),
                            ),
                            child: AspectRatio(
                              aspectRatio: 1 / 1,
                              child: Padding(
                                padding: const EdgeInsets.all(5.0),
                                child: Container(color: Colors.white,),
                              ),
                            ),
                          ),
                          // 文字区域用剩余空间,避免挤压正方形
                          Expanded(
                            child: Padding(
                              padding: const EdgeInsets.only(
                                  left: 2.0, right: 2.0),
                              child: FittedBox(
                                fit: BoxFit.fitWidth,
                                child: Text(
                                  'Test',
                                  style: TextStyle(
                                      fontSize: 12.0, color: Colors.black),
                                ),
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              );
            },
          );
        }
      ),
    );
  }
}
修改点说明
  • 新增LayoutBuilder包裹ListView,获取当前组件可用的实际宽度,不再依赖全局屏幕宽度做计算,适配所有父容器场景
  • 给每个Item的SizedBox同时指定height和width为相同逻辑的计算值,避免父级高度约束挤压内部正方形
  • 文字区域外层套Expanded,自动占满剩余空间,不会和正方形区域抢占高度

修改后可以适配安卓、iOS全尺寸设备,正方形区域始终保持1:1比例。

内容的提问来源于stack exchange,提问作者Mohammed Nabil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:57:02