snap 2.0.0
snap: ^2.0.0 copied to clipboard

An extensive snap tool/widget for Flutter that allows very flexible snap management and snapping between your widgets.

example/lib/main.dart

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// © Cosmos Software | Ali Yigit Bireroglu                                                                                                           /
// All material used in the making of this code, project, program, application, software et cetera (the "Intellectual Property")                     /
// belongs completely and solely to Ali Yigit Bireroglu. This includes but is not limited to the source code, the multimedia and                     /
// other asset files. If you were granted this Intellectual Property for personal use, you are obligated to include this copyright                   /
// text at all times.                                                                                                                                /
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//@formatter:off

import 'package:flutter/material.dart';

import 'package:snap/snap.dart';

List<GlobalKey> bounds = [];
List<GlobalKey> views = [];

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Snap Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MyHomePage(title: 'Snap Demo'),
    );
  }
}

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

  final String? title;

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

class _MyHomePageState extends State<MyHomePage> {
  double bottom = -200.0;

  @override
  void initState() {
    super.initState();

    for (int i = 0; i < 6; i++) {
      bounds.add(GlobalKey());
      views.add(GlobalKey());
    }
  }

  Widget description(String text) {
    return Container(
      constraints: const BoxConstraints.expand(height: 75),
      color: Colors.green,
      child: Center(
        child: Padding(
          padding: const EdgeInsets.all(10),
          child: Text(
            text,
            style: const TextStyle(
              color: Colors.white,
              fontWeight: FontWeight.bold,
              fontSize: 15,
            ),
            textAlign: TextAlign.center,
          ),
        ),
      ),
    );
  }

  Widget gap() {
    return Container(
      constraints: const BoxConstraints.expand(height: 25),
      color: Colors.transparent,
      child: Center(
        child: const Text(
          "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ",
          style: const TextStyle(
            color: Colors.black,
            fontWeight: FontWeight.bold,
            fontSize: 10,
          ),
          textAlign: TextAlign.center,
        ),
      ),
    );
  }

  Widget normalBox(Key key, String text, Color color) {
    return Container(
      key: key,
      width: 200,
      height: 200,
      color: Colors.transparent,
      child: Padding(
        padding: const EdgeInsets.all(5),
        child: Container(
          constraints: BoxConstraints.expand(),
          decoration: BoxDecoration(
            color: color,
            borderRadius: const BorderRadius.all(const Radius.circular(10.0)),
          ),
          child: Center(
            child: Text(
              text,
              style: const TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
                fontSize: 25,
              ),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ),
    );
  }

  Widget translatedBox(Key key, String text, Color color) {
    return Transform.translate(
      offset: const Offset(50, 50),
      child: Container(
        key: key,
        width: 200,
        height: 200,
        color: Colors.transparent,
        child: Padding(
          padding: const EdgeInsets.all(5),
          child: Container(
            constraints: BoxConstraints.expand(),
            decoration: BoxDecoration(
              color: color,
              borderRadius: const BorderRadius.all(const Radius.circular(10.0)),
            ),
            child: Center(
              child: Text(
                text,
                style: const TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 25,
                ),
                textAlign: TextAlign.center,
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget smallBox(Key key, String text, Color color) {
    return Container(
      key: key,
      width: 50,
      height: 50,
      color: Colors.transparent,
      child: Padding(
        padding: const EdgeInsets.all(5),
        child: Container(
          constraints: BoxConstraints.expand(),
          decoration: BoxDecoration(
            color: color,
            borderRadius: const BorderRadius.all(const Radius.circular(0.0)),
          ),
          child: Center(
            child: Text(
              text,
              style: const TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.bold,
                fontSize: 25,
              ),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ),
    );
  }

  Widget dottedBox(Key key, String text, Color color) {
    return Transform.translate(
      offset: const Offset(75, 100),
      child: Container(
        key: key,
        width: 200,
        height: 200,
        color: Colors.transparent,
        child: Stack(
          children: [
            Padding(
              padding: const EdgeInsets.all(5),
              child: Container(
                constraints: BoxConstraints.expand(),
                decoration: BoxDecoration(
                  color: color,
                  borderRadius: const BorderRadius.all(const Radius.circular(10.0)),
                ),
                child: Center(
                  child: Text(
                    text,
                    style: const TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                      fontSize: 25,
                    ),
                    textAlign: TextAlign.center,
                  ),
                ),
              ),
            ),
            Align(
              alignment: const Alignment(-0.9, -0.9),
              child: Container(
                width: 10,
                height: 10,
                color: Colors.orangeAccent,
              ),
            ),
            Align(
              alignment: const Alignment(0.9, -0.9),
              child: Container(
                width: 10,
                height: 10,
                color: Colors.black,
              ),
            ),
            Align(
              alignment: const Alignment(-0.9, 0.9),
              child: Container(
                width: 10,
                height: 10,
                color: Colors.deepPurpleAccent,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget firstNormalBoxView() {
    return normalBox(
      views[0],
      "Move & Snap",
      Colors.redAccent,
    );
  }

  Widget animatedBoxView() {
    return normalBox(
      views[1],
      "Move & Snap",
      Colors.redAccent,
    );
  }

  Widget dottedBoxView() {
    return dottedBox(
      views[2],
      "Move & Snap",
      Colors.redAccent,
    );
  }

  Widget translatedBoxView() {
    return translatedBox(
      views[3],
      "Move & Snap",
      Colors.redAccent,
    );
  }

  Widget smallBoxView() {
    return smallBox(
      views[4],
      "*",
      Colors.redAccent,
    );
  }

  Widget secondNormalBoxView() {
    return normalBox(
      views[5],
      "Move & Snap",
      Colors.redAccent,
    );
  }

  Widget thirdNormalBoxView() {
    return normalBox(
      views[6],
      "Move & Snap",
      Colors.redAccent,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title!)),
      body: PageView(
        onPageChanged: (int index) {
          if (index == 1)
            setState(() {
              bottom = 0.0;
            });
          else
            setState(() {
              bottom = -200.0;
            });
        },
        children: [
          Scaffold(
            body: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                description("The box will snap to the corners or the center."),
                gap(),
                Expanded(
                  child: Align(
                    key: bounds[0],
                    alignment: const Alignment(-1.0, -1.0),
                    child: SnapController(
                      firstNormalBoxView(),
                      true,
                      views[0],
                      bounds[0],
                      Offset.zero,
                      const Offset(1.0, 1.0),
                      const Offset(0.75, 0.75),
                      const Offset(0.75, 0.75),
                      snapTargets: [
                        const SnapTarget(Pivot.topLeft, Pivot.topLeft),
                        const SnapTarget(Pivot.topRight, Pivot.topRight),
                        const SnapTarget(Pivot.bottomLeft, Pivot.bottomLeft),
                        const SnapTarget(Pivot.bottomRight, Pivot.bottomRight),
                        const SnapTarget(Pivot.center, Pivot.center),
                      ],
                      minSnapDistance: 100,
                    ),
                  ),
                ),
              ],
            ),
          ),
          Scaffold(
            body: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                description("The box will snap to the closest side regardless of animation."),
                gap(),
                Expanded(
                  child: Align(
                    key: bounds[1],
                    alignment: const Alignment(-1.0, -1.0),
                    child: Stack(
                      children: [
                        AnimatedPositioned(
                          left: 0,
                          bottom: bottom,
                          duration: Duration(milliseconds: 300),
                          child: SnapController(
                            animatedBoxView(),
                            true,
                            views[1],
                            bounds[1],
                            Offset.zero,
                            const Offset(1.0, 1.0),
                            const Offset(0.75, 0.75),
                            const Offset(0.75, 0.75),
                            snapTargets: [
                              const SnapTarget(Pivot.closestAny, Pivot.closestAny),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
          Scaffold(
            body: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                description("The box will snap to the closest matching color."),
                gap(),
                Expanded(
                  child: Stack(
                    children: [
                      Align(
                        key: bounds[2],
                        alignment: const Alignment(-1.0, -1.0),
                        child: SnapController(
                          dottedBoxView(),
                          true,
                          views[2],
                          bounds[2],
                          Offset.zero,
                          const Offset(1.0, 1.0),
                          const Offset(0.75, 0.75),
                          const Offset(0.75, 0.75),
                          snapTargets: [
                            const SnapTarget(const Offset(0.1, 0.1), const Offset(0.1, 0.1)),
                            const SnapTarget(const Offset(0.9, 0.1), const Offset(0.85, 0.465)),
                            const SnapTarget(const Offset(0.1, 0.9), const Offset(0.1, 0.9)),
                          ],
                        ),
                      ),
                      Align(
                        alignment: const Alignment(-0.85, -0.85),
                        child: Container(
                          width: 10,
                          height: 10,
                          color: Colors.orangeAccent,
                        ),
                      ),
                      Align(
                        alignment: const Alignment(0.75, -0.1),
                        child: Container(
                          width: 10,
                          height: 10,
                          color: Colors.black,
                        ),
                      ),
                      Align(
                        alignment: const Alignment(-0.85, 0.85),
                        child: Container(
                          width: 10,
                          height: 10,
                          color: Colors.deepPurpleAccent,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
          Scaffold(
            body: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                description("The box will snap to the corners or the center while maintaining the initial offset"),
                gap(),
                Expanded(
                  child: Align(
                    key: bounds[3],
                    alignment: const Alignment(-1.0, -1.0),
                    child: SnapController(
                      translatedBoxView(),
                      true,
                      views[3],
                      bounds[3],
                      Offset(50.0 / MediaQuery.of(context).size.width, 50.0 / MediaQuery.of(context).size.height),
                      Offset(1.0, 1.0) - Offset(50.0 / MediaQuery.of(context).size.width, 50.0 / MediaQuery.of(context).size.height),
                      const Offset(0.75, 0.75),
                      const Offset(0.75, 0.75),
                      snapTargets: [
                        SnapTarget(Pivot.topLeft, Offset(50.0 / MediaQuery.of(context).size.width, 50.0 / MediaQuery.of(context).size.height)),
                        SnapTarget(Pivot.topRight, Offset(1.0 - 50.0 / MediaQuery.of(context).size.width, 50.0 / MediaQuery.of(context).size.height)),
                        SnapTarget(Pivot.bottomLeft, Offset(50.0 / MediaQuery.of(context).size.width, 1.0 - 50.0 / MediaQuery.of(context).size.height)),
                        SnapTarget(Pivot.bottomRight, Offset(1.0, 1.0) - Offset(50.0 / MediaQuery.of(context).size.width, 50.0 / MediaQuery.of(context).size.height)),
                        const SnapTarget(Pivot.center, Pivot.center),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
          Scaffold(
            body: Column(
              children: [
                description("The box will snap to the closest side or the center within its container."),
                gap(),
                Container(
                  width: 300,
                  height: 300,
                  color: Colors.orangeAccent,
                  child: Align(
                    key: bounds[4],
                    alignment: const Alignment(-1.0, -1.0),
                    child: SnapController(
                      smallBoxView(),
                      true,
                      views[4],
                      bounds[4],
                      Offset.zero,
                      const Offset(1.0, 1.0),
                      const Offset(0.15, 0.15),
                      const Offset(0.15, 0.15),
                      snapTargets: [
                        const SnapTarget(Pivot.closestAny, Pivot.closestAny),
                        const SnapTarget(Pivot.center, Pivot.center),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
          Scaffold(
            body: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                description("The box will snap to the corners or the center without animation."),
                gap(),
                Expanded(
                  child: Align(
                    key: bounds[5],
                    alignment: const Alignment(-1.0, -1.0),
                    child: SnapController(
                      secondNormalBoxView(),
                      false,
                      views[5],
                      bounds[5],
                      Offset.zero,
                      const Offset(1.0, 1.0),
                      const Offset(0.75, 0.75),
                      const Offset(0.75, 0.75),
                      snapTargets: [
                        const SnapTarget(Pivot.topLeft, Pivot.topLeft),
                        const SnapTarget(Pivot.topRight, Pivot.topRight),
                        const SnapTarget(Pivot.bottomLeft, Pivot.bottomLeft),
                        const SnapTarget(Pivot.bottomRight, Pivot.bottomRight),
                        const SnapTarget(Pivot.center, Pivot.center),
                      ],
                      animateSnap: false,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
11
likes
110
pub points
70%
popularity

Publisher

cosmossoftware.coffee

An extensive snap tool/widget for Flutter that allows very flexible snap management and snapping between your widgets.

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (LICENSE)

Dependencies

flick, flutter

More

Packages that depend on snap