stop_spring_simulation 0.0.1 copy "stop_spring_simulation: ^0.0.1" to clipboard
stop_spring_simulation: ^0.0.1 copied to clipboard

Creates a custom spring simulation with specified parameters.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:stop_spring_simulation/stop_spring_simulation.dart';

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late AnimationController controller;
  double pullValue = 0;
  double mass = 0.5;
  double stiffness = 100.0;
  double ratio = 1.0;

  @override
  void initState() {
    super.initState();
    controller = AnimationController.unbounded(vsync: this);
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  void _incrementCounter() {
    setState(() {
    });
  }

  startAnimation(Velocity? velocity, double target) {
    if (controller.isAnimating) {
      controller.stop();
    }
    print("velocity ${velocity?.pixelsPerSecond.dy}");
    final simulation = StopSpringSimulation(
      spring: SpringDescription.withDampingRatio(
        mass: mass,
        stiffness: stiffness,
        ratio: ratio,
      ),
      position: controller.value,
      velocity: velocity?.pixelsPerSecond.dy ?? 0,
      leadingExtent: target,
      trailingExtent: target,
    );
    controller.animateWith(simulation);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Stack(
        alignment: Alignment.center,
        children: [
          AnimatedBuilder(
            animation: controller,
            builder: (context, child) {
              return Positioned(top: 200 + controller.value, child: child!);
            },
            child: GestureDetector(
                onPanDown: (_) {
                  pullValue = 0;
                },
                onPanUpdate: (d) {
                  pullValue += d.delta.dy;
                  controller.value = pullValue;
                },
                onPanEnd: (d) {
                  startAnimation(d.velocity, 0);
                },
                child: Handle()),
          ),
          Positioned(
              child: Column(
            children: [
              InputNumber(
                onValueChanged: (double val) {
                  mass = val;
                },
                initValue: mass.toString(),
                title: 'Mass',
              ),
              InputNumber(
                onValueChanged: (double val) {
                  stiffness = val;
                },
                initValue: stiffness.toString(),
                title: 'Stiffness',
              ),
              InputNumber(
                onValueChanged: (double val) {
                  ratio = val;
                },
                initValue: ratio.toString(),
                title: 'Ratio',
              ),
            ],
          )),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

class InputNumber extends StatefulWidget {
  const InputNumber({super.key, required this.onValueChanged, required this.initValue, required this.title});

  final void Function(double val) onValueChanged;
  final String initValue;
  final String title;

  @override
  State<InputNumber> createState() => _InputNumberState();
}

class _InputNumberState extends State<InputNumber> {
  final controller = TextEditingController();

  @override
  void initState() {
    super.initState();
    controller.text = widget.initValue;
  }

  @override
  Widget build(BuildContext context) {
    bool valid = double.tryParse(controller.text) != null;
    return Row(
      children: [
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Text(widget.title),
        ),
        SizedBox(
            width: 80,
            child: TextField(
              controller: controller,
              keyboardType: TextInputType.number,
              decoration: InputDecoration(
                isCollapsed: true,
                isDense: true
              ),
              style: TextStyle(
                color: valid ? Colors.green : Colors.red,
              ),
              onChanged: (text) {
                final val = double.tryParse(text);
                if (val != null) {
                  widget.onValueChanged?.call(val);
                }
                setState(() {});
              },
            )),
      ],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 80,
      height: 80,
      decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.blue, boxShadow: [
        BoxShadow(
          color: Colors.black.withOpacity(0.3),
        )
      ]),
      child: Icon(Icons.back_hand_outlined),
    );
  }
}
0
likes
150
points
23
downloads

Publisher

unverified uploader

Weekly Downloads

Creates a custom spring simulation with specified parameters.

Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on stop_spring_simulation