Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter 3D Cube Effect

I'm asking you how I can create this effect in a Flutter?

enter image description here

like image 499
Cristian F. Bustos Avatar asked Jan 26 '23 10:01

Cristian F. Bustos


1 Answers

Probably you know that flutter doesn't have 3d engine. But you don't need it, you can use perspective transformations.

I've made small example for you.

enter image description here

import 'dart:math';

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 3D Cube Effect',
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: Scaffold(
          body: Container(
        child: SafeArea(
          top: true,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Text('Flutter 3D Cube Effect'),
              Expanded(
                child: Pseudo3dSlider(),
              ),
            ],
          ),
        ),
      )),
    );
  }
}

class Pseudo3dSlider extends StatefulWidget {
  @override
  _Pseudo3dSliderState createState() => _Pseudo3dSliderState();
}

class _Pseudo3dSliderState extends State<Pseudo3dSlider> {
  Map<String, Offset> offsets = {
    'start': Offset(70, 100),
    'finish': Offset(200, 100),
    'center': Offset(100, 200),
  };

  double originX = 0;
  double x = 0;

  void onDragStart(double originX) => setState(() {
        this.originX = originX;
      });

  void onDragUpdate(double x) => setState(() {
        this.x = originX - x;
      });

  double get turnRatio {
    const step = -150.0;
    var k = x / step;
    k = k > 1 ? 1 : (k < 0 ? 0 : k);
    return 1 - k;
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.opaque,
      onPanStart: (details) => onDragUpdate(details.globalPosition.dx),
      onPanUpdate: (details) => onDragUpdate(details.globalPosition.dx),
      child: Slider(
        children: [
          _Side(
            color: Colors.blueAccent,
            number: 1,
          ),
          _Side(
            color: Colors.redAccent.shade200,
            number: 2,
          ),
        ],
        k: turnRatio,
      ),
    );
  }
}

class _Side extends StatelessWidget {
  const _Side({Key key, this.color, this.number}) : super(key: key);

  final Color color;
  final int number;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 150,
      height: 150,
      color: color,
      child: Center(
        child: Text(
          number.toString(),
          style: TextStyle(fontSize: 14),
        ),
      ),
    );
  }
}

class Slider extends StatelessWidget {
  Slider({
    Key key,
    @required this.children,
    @required this.k,
  }) : super(key: key) {
    assert(children.length == 2, 'wronge nubmer of children');
  }

  final List<Widget> children;
  final double k;

  @override
  Widget build(BuildContext context) {
    var k1 = k;
    var k2 = 1 - k;
    print(k1);
    print(k2);
    return Row(
      children: <Widget>[
        Transform(
          transform: Matrix4.identity()
            ..setEntry(3, 2, 0.003)
            ..rotateY(pi / 2 * k1),
          alignment: FractionalOffset.centerRight,
          child: children[0],
        ),
        Transform(
          transform: Matrix4.identity()
            ..setEntry(3, 2, 0.003)
            ..rotateY(pi / 2 * -k2),
          alignment: FractionalOffset.centerLeft,
          child: children[1],
        )
      ],
    );
  }
}
like image 66
Kherel Avatar answered Feb 02 '23 22:02

Kherel