flutter_stage 0.0.1 icon indicating copy to clipboard operation
flutter_stage: ^0.0.1 copied to clipboard

A widget that positions its children in a 3D scene.

example/lib/main.dart

import 'package:flare_flutter/flare_actor.dart';
import 'package:flutter/material.dart';
import 'package:flutter_stage/flutter_stage.dart';
import 'package:intl/intl.dart';
import 'control.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Stage',
      theme: ThemeData.dark(),
      home: MyHomePage(title: 'Flutter Stage Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

/// Weather condition in English.
enum WeatherCondition {
  cloudy,
  foggy,
  rainy,
  snowy,
  sunny,
  thunderstorm,
  windy,
}

/// Temperature unit of measurement.
enum TemperatureUnit {
  celsius,
  fahrenheit,
}

class _MyHomePageState extends State<MyHomePage> {
  Scene scene;
  String _location = 'Mountain View, CA';
  num _temperature = 22.0;
  WeatherCondition _weatherCondition = WeatherCondition.sunny;
  TemperatureUnit _unit = TemperatureUnit.celsius;

  ClockTimeControl _clockControl = ClockTimeControl();
  ClockHandControl _clockHandControl = ClockHandControl();

  /// Temperature unit of measurement with degrees.
  String get unitString {
    switch (_unit) {
      case TemperatureUnit.fahrenheit:
        return '°F';
      case TemperatureUnit.celsius:
      default:
        return '°C';
    }
  }

  num _convertFromCelsius(num degreesCelsius) {
    switch (_unit) {
      case TemperatureUnit.fahrenheit:
        return 32.0 + degreesCelsius * 9.0 / 5.0;
      case TemperatureUnit.celsius:
      default:
        return degreesCelsius;
        break;
    }
  }

  num _convertToCelsius(num degrees) {
    switch (_unit) {
      case TemperatureUnit.fahrenheit:
        return (degrees - 32.0) * 5.0 / 9.0;
      case TemperatureUnit.celsius:
      default:
        return degrees;
        break;
    }
  }

  /// Removes the enum type and returns the value as a String.
  String enumToString(Object e) => e.toString().split('.').last;

  Widget _enumMenu<T>(String label, T value, List<T> items, ValueChanged<T> onChanged) {
    return InputDecorator(
      decoration: InputDecoration(
        labelText: label,
      ),
      child: DropdownButtonHideUnderline(
        child: DropdownButton<T>(
          value: value,
          isDense: true,
          onChanged: onChanged,
          items: items.map((T item) {
            return DropdownMenuItem<T>(
              value: item,
              child: Text(enumToString(item)),
            );
          }).toList(),
        ),
      ),
    );
  }

  Widget _textField(String currentValue, String label, ValueChanged<Null> onChanged) {
    return TextField(
      decoration: InputDecoration(
        hintText: currentValue,
        helperText: label,
      ),
      onChanged: onChanged,
    );
  }

  void _onSceneCreated(Scene scene) {
    this.scene = scene;
    scene.camera.position.setFrom(Vector3(0, 0, 1000));
    scene.camera.updateTransform();
  }

  Actor makeBlock({String name, Vector3 position, double size, List<Actor> faces}) {
    final double radius = size / 2 - size * 0.0015;
    return Actor(name: name, position: position, children: [
      Actor(name: faces[0].name, position: Vector3(0, 0, radius), rotation: Vector3(0, 0, 0), width: size, height: size, widget: faces[0].widget, children: faces[0].children),
      Actor(name: faces[1].name, position: Vector3(radius, 0, 0), rotation: Vector3(0, 90, 0), width: size, height: size, widget: faces[1].widget, children: faces[1].children),
      Actor(name: faces[2].name, position: Vector3(0, 0, -radius), rotation: Vector3(0, 180, 0), width: size, height: size, widget: faces[2].widget, children: faces[2].children),
      Actor(name: faces[3].name, position: Vector3(-radius, 0, 0), rotation: Vector3(0, 270, 0), width: size, height: size, widget: faces[3].widget, children: faces[3].children),
      Actor(name: faces[4].name, position: Vector3(0, -radius, 0), rotation: Vector3(90, 0, 0), width: size, height: size, widget: faces[4].widget, children: faces[4].children),
      Actor(name: faces[5].name, position: Vector3(0, radius, 0), rotation: Vector3(270, 0, 0), width: size, height: size, widget: faces[5].widget, children: faces[5].children),
    ]);
  }

  Widget makeBlockFace(double size) {
    return Container(
      width: size,
      height: size,
      decoration: BoxDecoration(
        border: Border.all(color: Color.fromRGBO(77, 77, 77, 1.0), width: size * 0.005),
        gradient: LinearGradient(
          colors: [Color.fromRGBO(25, 25, 25, 1.0), Color.fromRGBO(56, 56, 56, 1.0), Color.fromRGBO(25, 25, 25, 1.0)],
          stops: [0.1, 0.5, 0.9],
          begin: FractionalOffset.topRight,
          end: FractionalOffset.bottomLeft,
          tileMode: TileMode.repeated,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final double blockSize = 600;
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Stage(
        onSceneCreated: _onSceneCreated,
        children: [
          makeBlock(
            name: 'block',
            position: Vector3(0, 0, 0),
            size: blockSize * 1.1,
            faces: [
              Actor(
                name: 'front',
                widget: makeBlockFace(blockSize),
                children: [
                  Actor(
                    position: Vector3(0, 0, blockSize * 0.06),
                    width: blockSize,
                    height: blockSize,
                    widget: Container(key: ValueKey('hour'), child: FlareActor('assets/clock/hour.flr', animation: 'idle', controller: _clockControl)),
                  ),
                  Actor(
                    position: Vector3(0, 0, 0),
                    width: blockSize,
                    height: blockSize,
                    widget: Container(key: ValueKey('minute'), child: FlareActor('assets/clock/minute.flr')),
                  ),
                  Actor(
                    position: Vector3(0, 0, blockSize * 0.068),
                    width: blockSize,
                    height: blockSize,
                    widget: Container(key: ValueKey('hour_hand'), child: FlareActor('assets/clock/hand.flr', controller: _clockHandControl)),
                  ),
                ],
              ),
              Actor(
                name: 'right',
                widget: makeBlockFace(blockSize),
                children: [
                  Actor(
                    position: Vector3(0, 0, 0),
                    width: blockSize,
                    height: blockSize * 0.85,
                    widget: Stack(
                      children: <Widget>[
                        Align(
                          alignment: Alignment.topCenter,
                          child: Text(
                            DateFormat('MMMM').format(DateTime.now()),
                            style: TextStyle(fontSize: blockSize * 0.15, color: Colors.white.withOpacity(0.5)),
                          ),
                        ),
                        Align(
                          alignment: Alignment.bottomCenter,
                          child: Text(
                            DateFormat('EEEE').format(DateTime.now()),
                            style: TextStyle(fontSize: blockSize * 0.13, color: Colors.white.withOpacity(0.5)),
                          ),
                        )
                      ],
                    ),
                  ),
                  Actor(
                    position: Vector3(0, 0, blockSize * 0.02),
                    width: blockSize,
                    height: blockSize,
                    widget: Center(
                      child: Text(
                        DateFormat('d').format(DateTime.now()),
                        style: TextStyle(fontSize: blockSize * 0.5, fontWeight: FontWeight.bold, color: Colors.white.withOpacity(0.6)),
                      ),
                    ),
                  ),
                  Actor(
                    position: Vector3(0, 0, 0),
                    width: blockSize,
                    height: blockSize,
                    widget: Center(
                      child: Text(
                        DateFormat('d').format(DateTime.now()),
                        style: TextStyle(fontSize: blockSize * 0.5, fontWeight: FontWeight.bold, color: Colors.black.withOpacity(0.3)),
                      ),
                    ),
                  ),
                ],
              ),
              Actor(
                name: 'back',
                widget: makeBlockFace(blockSize),
                children: [
                  Actor(
                    position: Vector3(0, 0, 0),
                    width: blockSize * 0.8,
                    height: blockSize * 0.8,
                    widget: Column(
                      children: <Widget>[
                        _textField(_location, 'Location', (String location) {
                          setState(() {
                            _location = location;
                          });
                        }),
                        _textField(_convertFromCelsius(_temperature).toStringAsFixed(0), 'Temperature', (String temperature) {
                          setState(() {
                            _temperature = _convertToCelsius(double.parse(temperature));
                          });
                        }),
                        _enumMenu('Weather', _weatherCondition, WeatherCondition.values, (WeatherCondition condition) {
                          setState(() {
                            _weatherCondition = condition;
                          });
                        }),
                        _enumMenu('Units', _unit, TemperatureUnit.values, (TemperatureUnit unit) {
                          setState(() {
                            _unit = unit;
                          });
                        }),
                      ],
                    ),
                  ),
                ],
              ),
              Actor(
                name: 'left',
                widget: makeBlockFace(blockSize),
                children: [
                  Actor(
                    position: Vector3(0, 0, 0),
                    width: blockSize,
                    height: blockSize * 0.85,
                    widget: Stack(
                      children: <Widget>[
                        Align(
                          alignment: Alignment.topCenter,
                          child: FittedBox(child: Text(_location, style: TextStyle(fontSize: blockSize * 0.09, color: Colors.white.withOpacity(0.35)))),
                        ),
                        Align(
                          alignment: Alignment.bottomCenter,
                          child: Text(enumToString(_weatherCondition), style: TextStyle(fontSize: blockSize * 0.13, color: Colors.white.withOpacity(0.6))),
                        ),
                      ],
                    ),
                  ),
                  Actor(
                    position: Vector3(0, 0, blockSize * 0.02),
                    width: blockSize,
                    height: blockSize,
                    widget: Center(
                      child: Text(
                        _convertFromCelsius(_temperature).toStringAsFixed(0) + unitString,
                        style: TextStyle(fontSize: blockSize / 3, color: Colors.white.withOpacity(0.6)),
                      ),
                    ),
                  ),
                  Actor(
                    position: Vector3(0, 0, 0),
                    width: blockSize,
                    height: blockSize,
                    widget: Center(
                      child: Text(
                        _convertFromCelsius(_temperature).toStringAsFixed(0) + unitString,
                        style: TextStyle(fontSize: blockSize / 3, color: Colors.black.withOpacity(0.3)),
                      ),
                    ),
                  ),
                ],
              ),
              Actor(name: 'top', widget: makeBlockFace(blockSize)),
              Actor(name: 'bottom', widget: makeBlockFace(blockSize)),
            ],
          ),
        ],
      ),
    );
  }
}
18
likes
80
pub points
38%
popularity

Publisher

verified publisher iconfinal.dev

A widget that positions its children in a 3D scene.

Repository (GitHub)
View/report issues

Documentation

API reference

License

Apache-2.0 (LICENSE)

Dependencies

flutter, vector_math

More

Packages that depend on flutter_stage