Флаттер поставил AnimatedIcon вместо иконки AppBar - PullRequest
0 голосов
/ 30 марта 2020

в моем приложении я пытаюсь использовать AnimatedIcon вместо Appbar, leading значок, для смены контроллера AnimatedIcon я использую Provider пакет, но я получаю эту ошибку:

setState() or markNeedsBuild() called during build.

my AppBar:

AppBar(
  elevation: 8.0,
  titleSpacing: 0.0,
  automaticallyImplyLeading: true,
  leading: Consumer<AppBarAnimatedIconMode>(
      builder: (context, mode, child) => ValueListenableProvider.value(
          value: mode.iconMode,
          child: Consumer<bool>(
              builder: (context, value, child) => AppBarAnimatedIcon(
                    animate: value,
                  )))),

AppBarAnimatedIcon класс:

class AppBarAnimatedIcon extends StatefulWidget {
  final bool animate;

  const AppBarAnimatedIcon({@required this.animate});

  @override
  State<StatefulWidget> createState() => _AppBarAnimatedIcon();
}

class _AppBarAnimatedIcon extends State<AppBarAnimatedIcon> with TickerProviderStateMixin {
  AnimationController _animationController;
  bool get _animate => widget.animate;
  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 500));
    if(_animate){
      _animationController.forward();
    }else{
      _animationController.reverse();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedIcon(
        icon: AnimatedIcons.menu_close,
        progress: _animationController,
      ),
    );
  }
}

ValueNotifier класс для изменения AnimatedIcon контроллер анимации:

class AppBarAnimatedIconMode {
  final ValueNotifier<bool> iconMode = ValueNotifier<bool>(false);

  // ignore: use_setters_to_change_properties
  void changeIconMode() {
    iconMode.value = !iconMode.value;
  }
}

полное сообщение об ошибке:

This _DefaultInheritedProviderScope<bool> widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _DefaultInheritedProviderScope<bool>
  value: false
The widget which was currently being built when the offending call was made was: BuildDefaultAppBar
  dirty
  dependencies: [_EffectiveTickerMode]
  state: _BuildDefaultAppBar#a5ab5(tickers: tracking 1 ticker)
When the exception was thrown, this was the stack: 
#0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4167:11)
#1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4182:6)
#2      _InheritedProviderScopeMixin.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:269:5)
#3      _DeferredDelegateState.setState (package:provider/src/deferred_inherited_provider.dart:139:17)
#4      ValueListenableProvider._startListening.<anonymous closure>.<anonymous closure> (package:provider/src/value_listenable_provider.dart:74:38)
...
The ValueNotifier<bool> sending notification was: ValueNotifier<bool>#7aa18(true)  

1 Ответ

1 голос
/ 24 апреля 2020

Я создал новый проект и попробовал ваш код. Во-первых, если вы используете Provider, вы должны использовать ChangeNotifier с вашими классами управления. Также вы должны использовать ChangeNotifierProvider с вашим основным классом. Это мои коды, которые работают хорошо.

main.dart

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: ChangeNotifierProvider(
        create: (context) => AppBarAnimatedIconMode(), // This is condition class.
        child: Home(),
      ),
    );
  }
}

AppBarAnimatedIconMode.dart

class AppBarAnimatedIconMode with ChangeNotifier {
  final ValueNotifier<bool> iconMode = ValueNotifier<bool>(false);

  // ignore: use_setters_to_change_properties
  void changeIconMode() {
    iconMode.value = !iconMode.value;
    notifyListeners(); // For change the state of icon value.
  }
}

AppBarAnimatedIcon.dart

class AppBarAnimatedIcon extends StatefulWidget {
  final bool animate;

  const AppBarAnimatedIcon({@required this.animate});

  @override
  State<StatefulWidget> createState() => _AppBarAnimatedIcon();
}

class _AppBarAnimatedIcon extends State<AppBarAnimatedIcon> with SingleTickerProviderStateMixin {// You should use SingleTickerProviderStateMixin //
  AnimationController _animationController;

  bool get _animate => widget.animate;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(vsync: this, duration: const Duration(milliseconds: 500));
  }

  @override
  void dispose() { // Also dispose your animation when you dispose the class.
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_animate) { // You should check your conditions in your build() for animate
      _animationController.forward();
    } else {
      _animationController.reverse();
    }
    return Center(
      child: AnimatedIcon(
        icon: AnimatedIcons.menu_close,
        progress: _animationController,
      ),
    );
  }
}

Таким образом, вы можете управлять своей анимацией, как эта функция:

RaisedButton(
      child: Text('Change'),
      onPressed: () {
        var provider = Provider.of<AppBarAnimatedIconMode>(context, listen: false);
        provider.changeIconMode();
      },

Также на вашем AppBar вы можете использовать это код. У тебя все сложно.

AppBar(
    title: Text('Deneme'),
    leading: Consumer<AppBarAnimatedIconMode>(
      builder: (context, mode, child) => AppBarAnimatedIcon(
        animate: mode.iconMode,
      ),
    ),
  ),

А для AppBarAnimatedIconMode.dart

class AppBarAnimatedIconMode with ChangeNotifier {
  bool iconMode = false;

  void changeIconMode() {
    iconMode = !iconMode;
    notifyListeners();
  }
}
...