BeniaminoBaggins
BeniaminoBaggins

Reputation: 12503

Flutter -Temporary error - IconButton widgets require a Material widget ancestor

I get this error:

IconButton widgets require a Material widget ancestor

for about a second, then it goes away. It is complaining about an IconButton in one of my custom widgets. However the custom widget is placed in a page with a Scaffold. So the error should not exist since the custom button is inside a Scaffold material widget. When I wrap the usage of the button in its own tiny Scaffold, all is resolved. Why do I get this error temporarily? Is wrapping the custom widget in a tiny Scaffold considered a hack fix or an actual fix? All code and full error below:

Error:

The following assertion was thrown building IconButton(Icon, padding: EdgeInsets.zero, dirty):
No Material widget found.

IconButton widgets require a Material widget ancestor.
In material design, most widgets are conceptually "printed" on a sheet of material. In Flutter's material library, that material is represented by the Material widget. It is the Material widget that renders ink splashes, for instance. Because of this, many material library widgets require that there be a Material widget in the tree above them.

To introduce a Material widget, you can either directly include one, or use a widget that contains Material itself, such as a Card, Dialog, Drawer, or Scaffold.

The specific widget that could not find a Material ancestor was: IconButton
    Icon
    padding: EdgeInsets.zero
    dirty
The ancestors of this widget were
    VpBackButton
    Align
        alignment: centerLeft
        dependencies: [Directionality]
        renderObject: RenderPositionedBox#49b68 NEEDS-LAYOUT NEEDS-PAINT
    Expanded
        flex: 1
    Row
        direction: horizontal
        mainAxisAlignment: center
        crossAxisAlignment: center
        textBaseline: alphabetic
        dependencies: [Directionality]
        renderObject: RenderFlex#19d87 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
    GetMaterialApp
    App
    ...
The relevant error-causing widget was
IconButton
lib/…/back_button/back_button_widget.dart:18
When the exception was thrown, this was the stack
#0      debugCheckHasMaterial.<anonymous closure>
package:flutter/…/material/debug.dart:30
#1      debugCheckHasMaterial
package:flutter/…/material/debug.dart:52
#2      IconButton.build
package:flutter/…/material/icon_button.dart:330
#3      StatelessElement.build
package:flutter/…/widgets/framework.dart:4701
#4      ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4627
...
════════════════════════════════════════════════════════════════════════════════

It is complaining about my custom widget:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:vepo/presentation/modules/view.dart';

import 'back_button_widget_controller.dart';

class VpBackButton extends VpView<VpBackButtonController> {
  VpBackButton({this.onPressed}) {
    Get.put(VpBackButtonController());
  }

  @required
  final VoidCallback onPressed;
  AnimationController animateController;

  @override
  Widget build(BuildContext context) {
    return IconButton(
      padding: const EdgeInsets.all(0.0),
      icon: Icon(Icons.arrow_back_ios_rounded,
          color: Colors.white.withOpacity(0.5)),
      iconSize: 38,
      onPressed: () {
        controller.goBack(onPressed);
      },
    );
  }
}

The page that the button is inside contains a Scaffold which is a material widget:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:keyboard_avoider/keyboard_avoider.dart';
import 'package:reactive_forms/reactive_forms.dart';
import 'package:vepo/presentation/themes/home_theme.dart';
import 'package:vepo/presentation/widgets/display/buttons/back_button/back_button_widget.dart';
import 'package:vepo/presentation/widgets/display/buttons/elevated_buttons/elevated_submit_button_widget.dart';
import 'package:vepo/presentation/widgets/display/containers/gradient_container_widget.dart';
import 'package:vepo/presentation/widgets/display/text/subtitle_1_widget.dart';
import 'package:vepo/presentation/widgets/forms/text_field/text_field_widget.dart';
import 'package:vepo/presentation/widgets/pages/gradient_page_scaffold_widget.dart';

import '../../../../assets.gen.dart';
import 'logged_out_email_controller.dart';

class LoggedOutEmailView extends GetView<LoggedOutEmailController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomPadding: false,
        body: ConstrainedBox(
            constraints: BoxConstraints.tightFor(
                height: MediaQuery.of(context).size.height),
            child: VpGradientContainer(
                beginColor: initialGradientColor,
                endColor: endGradientColor,
                child: SafeArea(
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.end,
                        children: [
                      Expanded(
                          flex: 1,
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.start,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Expanded(
                                flex: 1,
                                child: Hero(
                                  tag: 'logoHero',
                                  child: Row(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.center,
                                      mainAxisAlignment:
                                          MainAxisAlignment.center,
                                      children: [
                                        Expanded(
                                            flex: 1,
                                            child: Align(
                                                alignment: Alignment.centerLeft,
                                                child: VpBackButton())),
                                        Expanded(
                                            flex: 1,
                                            child: Assets.images.logo.image()),
                                        Expanded(flex: 1, child: Container()),
                                      ]),
                                ),
                              ),
                            ],
                          )),

Upvotes: 2

Views: 2304

Answers (2)

Nimrod Dayan
Nimrod Dayan

Reputation: 3100

The issue you're seeing is a known bug in Flutter involving a Hero animation.

I see in your case that VpBackButton is under a Hero. If you remove the Hero, you'll see the error is gone. As per the linked bug above, currently there's only a workaround, which you've already discovered by yourself and it is to wrap the content of the Hero, in your case VpBackButton, with a Material widget.

child: Hero(
    tag: 'logoHero',
    child: Row( <--- wrap this with Material widget***************
        crossAxisAlignment:
            CrossAxisAlignment.center,
        mainAxisAlignment:
            MainAxisAlignment.center,
        children: [
        Expanded(
            flex: 1,
            child: Align(
                alignment: Alignment.centerLeft,
                child: VpBackButton())),

Upvotes: 1

hasan karaman
hasan karaman

Reputation: 1430

Since you wrapped VpBackButton flexible in LoggedOutEmailView, you cannot give a fixed size in VpBackButton. logic error. It is fixed if you remove iconsize or expanded.

Upvotes: 0

Related Questions