gskinnerTeam / flutter-defer-pointer

MIT License
60 stars 3 forks source link

Unexpected hit priority on `Flow`'s `children` property #2

Open raulmabe opened 2 years ago

raulmabe commented 2 years ago

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 ```dart 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 buttons; @override _AnimatedFloatingActionButtonsState createState() => _AnimatedFloatingActionButtonsState(); } class _AnimatedFloatingActionButtonsState extends State 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 ```dart AnimatedFloatingActionButtons( buttons: [ AnimatedFloatingActionButton( text: 'First extra button', icon: Icons.add_a_photo, onPressed: () {}, ), AnimatedFloatingActionButton( text: 'Second extra button', icon: Icons.add_alarm, onPressed: () {}, ), ], ), ```