황희윤
황희윤

Reputation: 613

Using setState in void function and get a warning that the void function(dynamic) cannot be assigned to the parameter type 'void Function()'

I'm getting a warning that The argument type 'void Function(dynamic)' can't be assigned to the parameter type 'void Function()' which is line right below the String dialogText. I used this function to pass data from Child widget, TopAppBar, to Parent widget which is MyApp. From the child widget, TopAppBar, I used TextFormField to type the word to change the text when it's submitted.

I saw the other codes that have no problem, so I don't know how to solve this problem.

Please help me! Thank you!

class MyApp extends StatefulWidget {
  MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int count = 0;
  var nameList = ['one','two','three','four'];
  String dialogText = "Hello!";

  void _changeDialogText(value){
    setState((value){
      dialogText = value;
    });
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
            appBar: TopAppBar(state: _changeDialogText,),
            body: Column(
              children: [
                Container(
                  height: 400,
                  child: (
                    ListView(
    children: List.generate(
        nameList.length, (index) => CustomListTile(title: nameList[index])),
                    )
                  )
                ),
                Container(
                  height: 20, child: Text(count.toString())
                ),
                Container(
                    height: 20, child: Text(dialogText)
                ),
              ],
            ),
          floatingActionButton: FloatingActionButton(
            child: Text('Button'),
            onPressed: (){
              print('a');
              setState(
                  (){
                    count++;
                  }
              );
            },
          ),
          bottomNavigationBar: BottomBar(),
            floatingActionButtonLocation: FloatingActionButtonLocation.endDocked
        );

  }
}
class TopAppBar extends StatefulWidget  with PreferredSizeWidget{
  const TopAppBar({Key? key, required this.state(value)}) : super(key: key);
  final Function(String value) state;

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
  State<TopAppBar> createState() => _TopAppBarState();
}


class _TopAppBarState extends State<TopAppBar> {
  final TopAppBarData _topAppBarData = TopAppBarData();
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  @override

  Widget build(BuildContext context) {
    return Form(
      child:
        AppBar(
            flexibleSpace: Container(
              decoration: BoxDecoration(
                  gradient: LinearGradient(
                      begin: Alignment.centerLeft,
                      end: Alignment.centerRight,
                      colors: <Color>[Color.fromRGBO(180, 44, 77, 1) , Color.fromRGBO(242, 114, 59, 1)]
                  )
              ),
            ),
          elevation: 0.0,
          centerTitle: false,
          title: Row(
            children: [
              Text(
                'SSG',
                style: TextStyle(
                  color: Colors.white,
                ),
              ),
              Icon(
                Icons.expand_more,
                color: Colors.black,
              )
            ],
          ),
          actions: [
            Padding(
                padding: EdgeInsets.only(right: 30.0),
                child: IconButton(
                  icon: Icon(Icons.search),
                    color: Colors.black,
                  onPressed: (){
                    showDialog(context: context, builder: (context){
                      return AlertDialog(
                        title: Text('Search'),
                        content: TextFormField(
                          onChanged: (value) {
                            widget.state(value);
                          },
                          decoration: InputDecoration(hintText: "Text Field in Dialog"),
                        ),
                        actions: <Widget>[
                          ElevatedButton(
                            child: Text('CANCEL'),
                            onPressed: () {
                              setState(() {
                                Navigator.pop(context);
                              });
                            },
                          ),
                          ElevatedButton(
                            child: Text('OK'),
                            onPressed: () {
                              setState(() {
                                Navigator.pop(context);
                              });
                            },
                          ),
                        ],
                      );
                    });
                  },
                )
            ),
            Padding(
                padding: EdgeInsets.only(right: 30.0),
                child: GestureDetector(
                  onTap: () {},
                  child: Icon(
                    Icons.menu,
                    color: Colors.black,
                  ),
                )
            ),
            Padding(
                padding: EdgeInsets.only(right: 30.0),
                child: GestureDetector(
                  onTap: () {},
                  child: Icon(
                    Icons.notification_add,
                    color: Colors.black,
                  ),
                )
            ),
          ],
        ),
    );
  }
}

Upvotes: 0

Views: 981

Answers (4)

Enam Kyei
Enam Kyei

Reputation: 86

Your problem stems from how you're setting your state. The setState function takes an argument of void Function() as seen below:

package:flutter/src/widgets/framework.dart 
void setState(void Function() fn)  
Containing class: State  Type: void Function(void Function())

However, you add an unnecessary argument value of type dynamic. Changing

 void _changeDialogText(value){
     setState((value){
         dialogText = value;
     });
 }

to

 void _changeDialogText(String value){
     setState((){
         dialogText = value;
    });
 }

will get rid of that warning. But you may want to consider using explicit types and force that by adding implicit-dynamic to your analysis options file.

Also, when initializing your final Function(String value) state; variable in the constructor, you use:

const TopAppBar({Key? key, required this.state(value)}) : super(key: key);

However, this is unnecessary and is missing a type on the "value" parameter. so you may use this instead:

const TopAppBar({Key? key, required this.state}) : super(key: key);

Upvotes: 1

Libertas
Libertas

Reputation: 408

the setState() function doesn't pass any arguments to the callback. The code should look like this:

setState(() {
    dialogText = value;
});

Upvotes: 2

nvoigt
nvoigt

Reputation: 77304

If you omit types, dynamic is assumed by the compiler. Don't do that. Turn on your linter (it should be on by default) and it will warn you about it.

final /* --> */ void /* <-- */  Function(String value) state;

and

void _changeDialogText( /* --> */ String /* <-- */ value){

Now, the signatures match.

Upvotes: 1

manhtuan21
manhtuan21

Reputation: 3455

change this

void _changeDialogText(value){
    setState((value){
      dialogText = value;
    });
  }

to

void _changeDialogText(String value){
        setState((value){
          dialogText = value;
        });
      }

Upvotes: 0

Related Questions