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

Flutter小屏幕适配问题:需保持UI原布局整体缩小而非滚动

解决Flutter蛇梯棋UI小屏幕适配问题(整体缩放无滚动)

核心改动思路

  • 用FittedBox包裹游戏核心区域,实现整体等比例缩放,确保布局完整显示且无滚动
  • 将固定像素的Positioned定位改为相对父容器的比例计算,避免小屏幕下元素错位
  • 用AspectRatio替代固定高度容器,保证棋盘网格的比例稳定
  • 移除硬编码的固定尺寸,改用相对比例让组件随缩放自适应

修改后的完整代码

@override
Widget build(BuildContext context) {
  // 定义基准缩放尺寸,取屏幕的90%作为基础参照
  final baseWidth = MediaQuery.of(context).size.width * 0.9;
  final baseHeight = MediaQuery.of(context).size.height * 0.9;

  return Scaffold(
    appBar: AppBar(
      title: const Text('Snake and Ladder'),
    ),
    body: Center(
      // 用FittedBox实现整体等比例缩放
      child: FittedBox(
        fit: BoxFit.contain,
        child: SizedBox(
          width: baseWidth,
          height: baseHeight,
          child: Stack(
            children: [
              Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  // 用AspectRatio保证棋盘宽高比稳定
                  AspectRatio(
                    aspectRatio: 1.25, // 对应网格childAspectRatio=0.8的反向比例
                    child: GridView.builder(
                      padding: const EdgeInsets.all(5.0),
                      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                        crossAxisCount: 10,
                        mainAxisSpacing: 10.0,
                        crossAxisSpacing: 0.1,
                        childAspectRatio: 0.8,
                      ),
                      itemCount: totalCells,
                      physics: const NeverScrollableScrollPhysics(),
                      shrinkWrap: true, // 让网格自适应父容器尺寸
                      itemBuilder: (context, index) {
                        // 保留原有的单元格构建逻辑
                        return _buildCell(...);
                      },
                    ),
                  ),
                  GestureDetector(
                    onTap: () {
                      setState(() {
                        // 保留原有的骰子点击逻辑
                      });
                    },
                    child: Card(
                      margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
                      color: _getPlayerColor(_buildCell1),
                      child: Padding(
                        padding: const EdgeInsets.all(10.0),
                        child: Image.asset(
                          'assets/images/dice-$_diceNumber.png',
                          // 移除固定宽度,让骰子随整体缩放
                        ),
                      ),
                    ),
                  ),
                ],
              ),
              // 蛇形图片改为相对比例定位
              Positioned(
                top: baseHeight * 0.417, // 原375/900的比例换算
                left: baseWidth * 0.244,  // 原220/900的比例换算
                child: Image.asset(
                  'assets/images/snake-1.png',
                  width: baseWidth * 0.111, // 原100/900的比例换算
                ),
              ),
              Positioned(
                top: baseHeight * 0.489, // 原440/900的比例换算
                left: baseWidth * 0.022,  // 原20/900的比例换算
                child: Image.asset(
                  'assets/images/snake-1.png',
                  width: baseWidth * 0.111,
                ),
              ),
              Positioned(
                top: baseHeight * 0.189, // 原170/900的比例换算
                left: baseWidth * 0.289,  // 原260/900的比例换算
                child: Image.asset(
                  'assets/images/snake-3.png',
                  width: baseWidth * 0.111,
                ),
              ),
              Positioned(
                top: baseHeight * 0.189, // 原170/900的比例换算
                left: baseWidth * 0.178,  // 原160/900的比例换算
                child: Image.asset(
                  'assets/images/snake-2.png',
                  width: baseWidth * 0.111,
                ),
              ),
            ],
          ),
        ),
      ),
    ),
  );
}

Widget _buildCell(int cellNumber, bool isPlayerLocation1, bool isPlayerLocation2) {
  bool isSnake = snakes.containsKey(cellNumber);
  return Container(
    decoration: BoxDecoration(
      border: Border.all(
        color: Colors.black,
        width: 1.0,
      ),
      color: _getCellColor(cellNumber),
    ),
    child: Center(
      child: Stack(
        children: [
          Icon(
            _locationIcon,
            size: 30.0,
            color: isPlayerLocation1 ? Colors.red : Colors.transparent,
          ),
          Icon(
            _locationIcon2,
            size: 30.0,
            color: isPlayerLocation2 ? Color.fromARGB(255, 199, 75, 248) : Colors.transparent,
          ),
          if (isSnake)
            Icon(
              Icons.arrow_downward,
              size: 20.0,
              color: Colors.brown,
            ),
          Text(
            '$cellNumber',
            style: const TextStyle(fontSize: 10.0),
          ),
        ],
      ),
    ),
  );
}

关键说明

  1. FittedBox:通过BoxFit.contain确保整个游戏区域按屏幕尺寸等比例缩放,完全显示所有内容,不会出现溢出或滚动
  2. 相对定位:所有蛇形图片的top/left和尺寸都基于基准宽高的比例计算,保证在任何屏幕尺寸下位置和大小相对棋盘保持一致
  3. AspectRatio:固定棋盘的宽高比,避免网格单元格在不同屏幕上变形
  4. 自适应组件:移除骰子的固定宽度,让它随整体缩放保持比例协调

内容的提问来源于stack exchange,提问作者Soumen Pramanik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 08:55:57