No Material widget found. Hero Animation is not working with TextField

278

The error message you got already explains the problem very well, so I'll just give you a solution. Wrap the child of your Hero widget in a Material:

Hero(
  tag: "search",
  child: Material(
    type: MaterialType.transparency,
    child: Row(
      children: [
        //TextField(),
        //GestureDetector(),
      ],
    ),
  ),
);
Share:
278
Akbar Pulatov
Author by

Akbar Pulatov

Engineer of Embedded Systems

Updated on December 31, 2022

Comments

  • Akbar Pulatov
    Akbar Pulatov over 1 year

    I want to achieve this animation with TextField:

    enter image description here

    but getting this instead:

    enter image description here

    Here is my TextField widget:

    import 'package:flutter/material.dart'; import 'package:line_awesome_flutter/line_awesome_flutter.dart'; import 'package:move_me_delivery/data/styles.dart';
    
    class SearchTextField extends StatefulWidget {   const SearchTextField({Key? key,
        this.onFocusChange,
        this.focus,
        this.onCancel,
        this.inputDecoration   }) : super(key: key);
    
      final void Function(bool hasFocus)? onFocusChange;   final FocusNode? focus;   final VoidCallback? onCancel;   final InputDecoration? inputDecoration;
    
    
    
    
      @override   _SearchTextFieldState createState() =>
    _SearchTextFieldState(); }
    
    class _SearchTextFieldState extends State<SearchTextField> {   FocusNode _focus = new FocusNode();
    
      @override   void initState() {
        super.initState();
        _focus = widget.focus ?? new FocusNode();
        _focus.addListener(
          (){
            if(widget.onFocusChange != null){
              widget.onFocusChange!(_focus.hasFocus);
            }
          }
        );   }
    
      @override   Widget build(BuildContext context) {
        return Hero(
          tag: "search",
          child: Row(
            children: [
    
              Expanded(
                child: TextField(style: AppTextStyles.body2,
                    focusNode: _focus,
                    decoration: InputDecoration(
                      prefixIcon: Icon(LineAwesomeIcons.search, color: Colors.black,),
                      // suffixIcon: Text("Cancel"),
                      filled: true,
                      fillColor: Colors.white,
                      border: OutlineInputBorder(borderRadius: BorderRadius.circular(8),
                          borderSide: const BorderSide(color: Colors.blue, width: 1))
                    ))),
    
              if(widget.onCancel != null)
              GestureDetector(
                onTap: widget.onCancel,
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text("Cancel"),
                ),
              )
            ],
          ),
        );   } }
    

    And here is my first screen:

    import 'package:flutter/material.dart';
    import 'package:get/get.dart';
    import 'package:move_me_delivery/components/rounded_app_bar.dart';
    import 'package:move_me_delivery/components/search_field.dart';
    import '../screens.dart';
    
    class HomeTab extends StatelessWidget {
      const HomeTab({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: RoundedAppBar(title: ""),
          body: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
            child: Column(
              children: [
                SearchTextField(
                  onFocusChange: (val) async {
                    if(val){
    
                      Navigator.push(
                          context,
                          PageRouteBuilder(
                              transitionDuration: Duration(seconds: 3),
                              pageBuilder: (_, __, ___) => SearchScreen()));
    
                      // await Get.to(() => SearchScreen());
                    }
                  },
    
                )
              ],
            ),
          )
        );
      }
    }
    

    and here is my second screen:

    import 'package:flutter/material.dart';
    import 'package:line_awesome_flutter/line_awesome_flutter.dart';
    import 'package:move_me_delivery/components/search_field.dart';
    import 'package:move_me_delivery/data/styles.dart';
    
    class SearchScreen extends StatefulWidget {
      const SearchScreen({Key? key}) : super(key: key);
    
      @override
      _SearchScreenState createState() => _SearchScreenState();
    }
    
    class _SearchScreenState extends State<SearchScreen> {
      final _focusNode = FocusNode();
    
      @override
      void initState() {
        super.initState();
        _focusNode.requestFocus();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          color: Colors.white,
          child: SafeArea(
            child: Scaffold(
              body: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
    
                child: Column(
                  children: [
                    SearchTextField(
                      focus: _focusNode,
                      onCancel: (){
                        FocusScope.of(context).unfocus();
                        Navigator.pop(context);
                      },
                      inputDecoration: InputDecoration(
                          prefixIcon: Icon(LineAwesomeIcons.search, color: Colors.black,),
                          filled: true,
                          fillColor: Colors.white,
                          border: OutlineInputBorder(borderRadius: BorderRadius.circular(8),
                              borderSide: const BorderSide(color: Colors.blue, width: 1))
                      ),
                    ),
    
    
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    

    My console:

    ======== Exception caught by widgets library =======================================================
    The following assertion was thrown building TextField(focusNode: FocusNode#0fba2, decoration: InputDecoration(prefixIcon: Icon(IconData(U+0F002), color: Color(0xff000000)), filled: true, fillColor: Color(0xffffffff), border: OutlineInputBorder()), style: TextStyle(inherit: true, color: Color(0xff000000), size: 15.0, weight: 400, style: normal), dirty, dependencies: [MediaQuery, UnmanagedRestorationScope], state: _TextFieldState#43a28):
    No Material widget found.
    
    TextField 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: TextField
      focusNode: FocusNode#0fba2
      decoration: InputDecoration(prefixIcon: Icon(IconData(U+0F002), color: Color(0xff000000)), filled: true, fillColor: Color(0xffffffff), border: OutlineInputBorder())
      style: TextStyle(inherit: true, color: Color(0xff000000), size: 15.0, weight: 400, style: normal)
      dirty
      dependencies: [MediaQuery, UnmanagedRestorationScope]
      state: _TextFieldState#43a28
    The ancestors of this widget were: 
      : Expanded
        flex: 1
      : Row
        direction: horizontal
        mainAxisAlignment: start
        crossAxisAlignment: center
        dependencies: [Directionality]
        renderObject: RenderFlex#afc02
      : GetMaterialApp
      : MyApp
      ...
    The relevant error-causing widget was: 
      TextField file:///Users/akbarpulatov/Desktop/tests/move_me_delivery/lib/components/search_field.dart:49:20
    When the exception was thrown, this was the stack: 
    #0      debugCheckHasMaterial.<anonymous closure> (package:flutter/src/material/debug.dart:27:7)
    #1      debugCheckHasMaterial (package:flutter/src/material/debug.dart:48:4)
    #2      _TextFieldState.build (package:flutter/src/material/text_field.dart:1116:12)
    #3      StatefulElement.build (package:flutter/src/widgets/framework.dart:4691:27)
    #4      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4574:15)
    ...
    ====================================================================================================