Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected hit priority on Flow's children property #2

Open
raulmabe opened this issue Jan 15, 2022 · 0 comments
Open

Unexpected hit priority on Flow's children property #2

raulmabe opened this issue Jan 15, 2022 · 0 comments

Comments

@raulmabe
Copy link

Hi, I am trying to implement several FABs through the Flow widget.

Context

What defers my case from your example is that I want to have the button that expands/shrinks the Flowfrom now on menu button– is at position 0 of the children property, thus keeping it immobile. For this reason, my FlowDelegate paints the children from last to first; so when all buttons are shrunk, my menu button is painted above the others.

This video section may clear out my intentions.

Problem

My problem starts when using this package. When all widgets are shrunk, the pointer event triggers the last button, not my menu button, thus not working properly.

Expected output

Trigger the menu button (GradientFAB) onPressed property, as its painted last and above the others.

Actual output

Triggers 'Second extra button', while being painted under the menu button.

Files

Widget file
import 'dart:developer';
import 'dart:math' as math;
import 'dart:ui';

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

class AnimatedFloatingActionButton {
  const AnimatedFloatingActionButton({
    required this.text,
    required this.icon,
    this.onPressed,
  });
  final String text;
  final IconData icon;
  final VoidCallback? onPressed;
}

const kPadding = 8.0;
const fabSize = 56.0;

class AnimatedFloatingActionButtons extends StatefulWidget {
  const AnimatedFloatingActionButtons({
    Key? key,
    required this.buttons,
  }) : super(key: key);

  final List<AnimatedFloatingActionButton> buttons;

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

class _AnimatedFloatingActionButtonsState
    extends State<AnimatedFloatingActionButtons>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late CurvedAnimation _curvedAnimation;

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

    _controller = AnimationController(
      duration: 300.ms,
      vsync: this,
    );
    _curvedAnimation =
        CurvedAnimation(parent: _controller, curve: Curves.decelerate);
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: fabSize,
      width: fabSize,
      child: DeferPointer(
        paintOnTop: true,
        child: Flow(
          clipBehavior: Clip.none,
          delegate: _MyFlowDelegate(
            animation: _curvedAnimation,
          ),
          children: [
            DeferPointer(
              // paintOnTop: true,
              child: GradientFAB(
                onPressed: _toggleAnimation,
                child: AnimatedBuilder(
                  animation: _curvedAnimation,
                  builder: (ctx, child) => Transform.rotate(
                    angle: lerpDouble(
                      0,
                      (90 + 45) * (math.pi / 180),
                      _controller.value,
                    )!,
                    child: child,
                  ),
                  child: const Icon(
                    Icons.add,
                    color: Colors.white,
                    size: 40.0,
                  ),
                ),
              ),
            ),
            ...widget.buttons
                .map(buildButton)
                .map((e) => DeferPointer(child: e))
                .toList(),
          ],
        ),
      ),
    );
  }

  Widget buildButton(AnimatedFloatingActionButton button) {
    return AnimatedBuilder(
      animation: _curvedAnimation,
      builder: (context, child) {
        return FloatingActionButton(
          isExtended: true,
          elevation: lerpDouble(0, 6.0, _controller.value),
          heroTag: button.text,
          child: child!,
          backgroundColor: context.colorScheme.primaryVariant,
          onPressed: () => log(button.text), //button.onPressed,
        );
      },
      child: Icon(button.icon),
    );
  }

  void _toggleAnimation() {
    if (_controller.status == AnimationStatus.completed) {
      _controller.reverse();
    } else {
      _controller.forward();
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    _curvedAnimation.dispose();
    super.dispose();
  }
}

class _MyFlowDelegate extends FlowDelegate {
  const _MyFlowDelegate({
    required this.animation,
  });
  final Animation animation;

  @override
  void paintChildren(FlowPaintingContext context) {
    final size = context.size;
    final xStart = size.width - fabSize;
    final yStart = size.height - fabSize;

    for (var i = context.childCount - 1; i >= 0; --i) {
      final offset = i * animation.value * (fabSize + kPadding);
      context.paintChild(
        i,
        transform: Matrix4.translationValues(
          xStart,
          yStart - offset,
          0,
        ),
      );
    }
  }

  @override
  bool shouldRepaint(covariant _MyFlowDelegate oldDelegate) {
    return animation != oldDelegate.animation;
  }
}
Example of use
           AnimatedFloatingActionButtons(
                buttons: [
                  AnimatedFloatingActionButton(
                    text: 'First extra button',
                    icon: Icons.add_a_photo,
                    onPressed: () {},
                  ),
                  AnimatedFloatingActionButton(
                    text: 'Second extra button',
                    icon: Icons.add_alarm,
                    onPressed: () {},
                  ),
                ],
              ),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant