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

Flutter立方体开发问题:旋转时部分面透明度异常

解决Flutter立方体旋转时部分面透明的问题

问题现象

实现Flutter立方体后,旋转时发现两个面保持不透明,其余面呈现透明状态,效果如下:
立方体旋转透明问题

问题原因

  1. Stack组件的绘制逻辑:Stack按子组件添加顺序绘制,后面的组件会强制覆盖前面的,3D旋转时无法根据Z轴位置自动调整层级,导致本该在前面的面被后面的面遮挡,视觉上呈现透明。
  2. 缺少透视矩阵:最外层Transform未设置透视参数,3D空间的深度感知错误,进一步放大了层级显示问题。
  3. 默认无深度测试支持:常规Transform+Stack组合不具备3D深度测试能力,无法依据Z轴坐标判断面的前后关系。

解决方案

使用Flutter原生的SceneBuilder绘制立方体,它默认支持深度测试,能根据3D空间的Z轴位置自动处理面的层级,同时添加透视矩阵保证正确的3D效果。修改后的完整代码如下:

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cube',
      theme: ThemeData(primarySwatch: Colors.blue),
      debugShowCheckedModeBanner: false,
      home: const Cube(),
    );
  }
}

class Cube extends StatefulWidget {
  const Cube({Key? key}) : super(key: key);

  @override
  _CubeState createState() => _CubeState();
}

class _CubeState extends State<Cube> {
  Offset offset = Offset.zero;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Cube"), backgroundColor: Colors.green),
      body: GestureDetector(
        onPanUpdate: (details) => setState(() => offset += details.delta),
        child: Center(
          child: CustomPaint(
            size: const Size(200, 200),
            painter: CubePainter(
              rotationX: -offset.dy * pi / 180,
              rotationY: -offset.dx * pi / 180,
            ),
          ),
        ),
      ),
    );
  }
}

class CubePainter extends CustomPainter {
  final double rotationX;
  final double rotationY;

  CubePainter({required this.rotationX, required this.rotationY});

  @override
  void paint(Canvas canvas, Size size) {
    final sceneBuilder = SceneBuilder();
    final paint = Paint()..style = PaintingStyle.fill;

    // 主旋转矩阵,添加透视效果
    final matrix = Matrix4.identity()
      ..perspective(0.001)
      ..rotateX(rotationX)
      ..rotateY(rotationY)
      ..translate(size.width / 2, size.height / 2);

    // 绘制后侧面(Z=-100)
    sceneBuilder.pushTransform(matrix.clone()..translate(0, 0, -100).storage);
    paint.color = Colors.amber;
    _drawFace(sceneBuilder, paint);
    sceneBuilder.pop();

    // 绘制左侧面
    sceneBuilder.pushTransform(matrix.clone()..translate(-100, 0, 0)..rotateY(-pi/2).storage);
    paint.color = Colors.red;
    _drawFace(sceneBuilder, paint);
    sceneBuilder.pop();

    // 绘制前侧面(Z=100)
    sceneBuilder.pushTransform(matrix.clone()..translate(0, 0, 100).storage);
    paint.color = Colors.blue;
    _drawFace(sceneBuilder, paint);
    sceneBuilder.pop();

    // 绘制右侧面
    sceneBuilder.pushTransform(matrix.clone()..translate(100, 0, 0)..rotateY(-pi/2).storage);
    paint.color = Colors.purple;
    _drawFace(sceneBuilder, paint);
    sceneBuilder.pop();

    // 渲染场景,自动处理深度层级
    final scene = sceneBuilder.build();
    canvas.renderScene(scene);
    scene.dispose();
  }

  void _drawFace(SceneBuilder builder, Paint paint) {
    final path = Path()
      ..addRect(const Rect.fromLTWH(-100, -100, 200, 200));
    builder.addPath(path, Offset.zero, paint: paint);
  }

  @override
  bool shouldRepaint(covariant CubePainter oldDelegate) {
    return oldDelegate.rotationX != rotationX || oldDelegate.rotationY != rotationY;
  }
}

如果不想使用SceneBuilder,也可以通过第三方库(如flutter_widgets中的Transform3D)快速实现深度测试,不过上述原生代码方案无需依赖外部包,更稳定可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 23:40:28