1

I'm trying to apply a 3D transformation (specifically a perspective + Y-axis rotation) to a widget in Flutter using Transform. The visual result is close to what I want, but I noticed the parent layout seems to calculate size before the transform is applied, so the layout doesn't fit the rotated child properly.

I've wrapped the Transform widget with widgets like SizedBox, Container, and ConstrainedBox (with fixed and dynamic sizes), hoping it would adapt to the post-transform size of the child. But no luck — the layout still behaves like the child was never transformed.

This becomes especially tricky when building dynamic layouts, where multiple transformed cards overlap or need to be positioned precisely based on their post-transform bounds.

I'm open to suggestions — is there a better way to handle this kind of 3D visual effect while still maintaining proper layout sizing?

Original Container (no transform)

Container dimensions

After Applying Transform

Transform dimensions

Here’s a minimal reproducible example of what I’ve built so far:

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

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(body: Center(child: TransformedCard())),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    const double itemWidth = 130;
    const double itemHeight = 180;

    final Matrix4 itemTransform = Matrix4.identity()
      ..setEntry(3, 2, 0.004) // Perspective
      ..rotateY(math.pi / 8); // 3D rotation

    return Transform(
      alignment: Alignment.centerRight,
      transform: itemTransform,
      filterQuality: FilterQuality.low,
      child: Container(
        width: itemWidth,
        height: itemHeight,
        decoration: BoxDecoration(
          color: Colors.green,
          borderRadius: BorderRadius.circular(12),
        ),
        child: const Center(
          child: Text(
            'Card',
            style: TextStyle(
              color: Colors.white,
              fontWeight: FontWeight.bold,
              fontSize: 16,
            ),
          ),
        ),
      ),
    );
  }
}

Ideally, I want the widget’s actual layout bounds to reflect the transformed size, so that I can:

  • Position it accurately relative to other widgets.

  • Avoid visual clipping or overflow.

  • Allow auto-sizing or wrapping logic to "see" the visual space it occupies after the transformation.

Is there a technique, Flutter layout trick, or even a lower-level custom render box that could help achieve this? Or maybe a completely different approach to achieve a similar 3D effect where layout and transform play nicely?

Any help or insight would be appreciated!

3
  • 1
    '''... or even a lower-level custom render box''' - yep, most likely you need a custom SingleChildRenderObjectWidget, you could check the sources of RotatedBox, its docs say: '''A widget that rotates its child by a integral number of quarter turns. Unlike Transform, which applies a transform just prior to painting, this object applies its rotation prior to layout, which means the entire rotated box consumes only as much space as required by the rotated child.''', sources: github.com/flutter/flutter/blob/main/packages/flutter/lib/src/… Commented Jul 31 at 10:01
  • and if you dont know how to paint the child widget refer to RenderTransform sources Commented Aug 1 at 18:38
  • If you know the ratio between old widget and new widget(which might need to be calculated by yourself), wrap it with Align with widthFactor or heightFactor properties. Commented Sep 12 at 0:00

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.