Анимированные FloatingActionButton в стеке не вызывают событие onPressed - PullRequest
0 голосов
/ 03 апреля 2019

Я создал анимированное меню с плавающей кнопкой действий (FAB): Основной FAB, который порождает другие FAB при нажатии. Он основан на нескольких онлайн-уроках.

Прекрасно работает, кроме одной серьезной проблемы: Созданные FAB не вызывают событие onPressed.

Кажется, что есть проблема с комбинацией анимации преобразования и виджета стека (от которого FAB являются потомками). Работает нормально, если заменить стек на строку ...

Похоже, что проблема была решена здесь, но без правильного решения: FloatingActionButton onPressed не запускается

Вот полный код этого меню FAB. Просто предоставьте ему список данных кнопок, подобный этому:

List<Map<String, dynamic>> _buttonsData = [
{'color': Colors.green ,'icon': Icons.stop},
{'color': Colors.blue ,'icon': Icons.subway},
{'color': Colors.green ,'icon': Icons.add},];
FancyFab2(_buttonsData, null)

код:

import 'package:flutter/material.dart';


class FancyFab extends StatefulWidget {
  FancyFab(this._buttonsData, this._onSelected);

  final List<Map<String, dynamic>> _buttonsData;
  final ValueChanged<int> _onSelected;

  @override
  createState() => FancyFabState(_buttonsData, _onSelected);
}

class FancyFabState extends State<FancyFab> with SingleTickerProviderStateMixin {
  final List<Map<String, dynamic>> _buttonsData;
  final ValueChanged<int> _onSelected;

  // state vars
  AnimationController _controller;
  Animation <double> _transform;

  bool _isOpened = false;

  FancyFabState(this._buttonsData, this._onSelected);

  @override
  void initState() {
    // call base
    super.initState();

    // _controller
    _controller = AnimationController(
      duration: Duration(milliseconds: 100),
      vsync: this
    );

    _transform = Tween<double>(
      begin: 0.0,
      end: -64.0,
    ).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Curves.fastOutSlowIn
      ),
    );
  }

  @override
  void dispose() {
    // controller
    _controller.dispose();

    // call base
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _buildFab(_controller);
  }

  Widget _buildFab(AnimationController controller) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, builder) {
        return Stack(
          children: List.generate(_buttonsData.length, (index) => _buildStackWidget(context, index))
        );
      }
    );
  }

  Widget _buildStackWidget(BuildContext context, int index) {
    Map<String, dynamic> buttonData = _buttonsData[index];
    if (index == _buttonsData.length - 1)
      return _buildMenuButton(index, buttonData);
    else
      return _buildMenuItem(index, buttonData);
  }

  Widget _buildMenuItem(int index, Map<String, dynamic> buttonData) {
    return Transform.translate(
      offset: Offset((1 + index) * _transform.value, 0.0),
      child: FloatingActionButton(
        heroTag: 100 + index,
        backgroundColor: buttonData['color'],
        //onPressed: () => _onSelected(index),
        onPressed: () => print('click'),
        child: Icon(buttonData['icon']),
      ),
    );
  }

  Widget _buildMenuButton(int index, Map<String, dynamic> buttonData) {
    return FloatingActionButton(
      heroTag: 200,
      backgroundColor: buttonData['color'],
      onPressed: _toggle,
      child: Icon(buttonData['icon']),
    );
  }

  void _toggle() {
    print('toggle');
    _isOpened = !_isOpened;
    if (true == _isOpened)
      _controller.forward();
    else
      _controller.reverse();
  }

}

1 Ответ

0 голосов
/ 04 апреля 2019

Это потому, что вы перемещаете items за пределы Stack, поэтому вы не можете hitTest на этих позициях.

Я изменил несколько строк вашего кода, чтобы он заработал:

  • Добавьте ограничения к вашему Stack (вы также можете использовать SizedBox), я использую контейнер для установки другого цвета фона.

          Widget _buildFab(AnimationController controller) {
            return AnimatedBuilder(
                animation: controller,
                builder: (context, builder) {
                  return Container(
                    width: MediaQuery.of(context).size.width,
                    height: 100,
                    color: Colors.blueGrey,
                    child: Stack(
                        children: List.generate(_buttonsData.length,
                            (index) => _buildStackWidget(context, index))),
                  );
                });
          }
    
  • Отцентрируйте items

        Widget _buildMenuItem(int index, Map<String, dynamic> buttonData) {
            return Center(
              child: Transform.translate(
                offset: Offset((1 + index) * _transform.value, 0.0),
                child: FloatingActionButton(
                  heroTag: 100 + index,
                  backgroundColor: buttonData['color'],
                  //onPressed: () => _onSelected(index),
                  onPressed: () => print('click'),
                  child: Icon(buttonData['icon']),
                ),
              ),
            );
          }
    
          Widget _buildMenuButton(int index, Map<String, dynamic> buttonData) {
            return Center(
              child: FloatingActionButton(
                heroTag: 200,
                backgroundColor: buttonData['color'],
                onPressed: _toggle,
                child: Icon(buttonData['icon']),
              ),
            );
          }
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...