简体   繁体   中英

Flutter: ListView scrolls back to origin when setState is called

I have a horizontal ListView with a bunch of Icons. When a user clicks on an Icon, I call setState to track the index of the selected item (so I can highlight it).

The problem is that whenever an item is selected, the ListView scrolls right back to the beginning (see the GIF below):

单击时 ListView 重置位置

Here's the code:

class _FormScreenState extends State<FormScreen> {
  int selectedCategory = 0;
  final categories = [
    {'icon': Icons.shopping_basket, 'category': 'Shopping'},
    {'icon': Icons.local_cafe, 'category': 'Eating out'},
    // ....
  ];

  Widget build(BuildContext context) {
    final _formKey = GlobalKey<FormState>();

    return Form(
      key: _formKey,
      child: SafeArea(
        child: Container(
          margin: EdgeInsets.symmetric(horizontal: 10.0),
          child: Column(
            children: <Widget>[
              SizedBox(height: 40.0),
              Text('Some money disappeared 💸',
                  style: TextStyle(fontSize: 24.0)),
              SizedBox(height: 40.0),
              TextFormField(
                autofocus: true,
                controller: _ctrlTxtAmount,
                keyboardType: TextInputType.number,
                decoration: InputDecoration(
                  hintText: 'AED ...',
                ),
                focusNode: fcsNodeTxtAmount,
                style: TextStyle(fontSize: 22),
                validator: (value) {
                  if (value.isEmpty || double.tryParse(value) == null) {
                    return "Amount needs to be a number";
                  }

                  return null;
                },
              ),
              SizedBox(height: 30.0),
              Container(
                height: 70.0,
                child: ListView.builder(
                  scrollDirection: Axis.horizontal,
                  itemCount: categories.length,
                  itemBuilder: (BuildContext context, int index) {
                    return Container(
                        padding: const EdgeInsets.all(12.0),
                        child: GestureDetector(
                          onTap: () {
                            setState(() {
                              selectedCategory = index;
                            });
                          },
                          child: Icon(categories[index]['icon'],
                              size: 40.0,
                              color: selectedCategory == index
                                  ? Colors.purple
                                  : Colors.grey),
                        ));
                  },
                ),
              ),
              SizedBox(
                height: 20.0,
              ),
              TextField(
                controller: _ctrlTxtDescription,
                decoration: InputDecoration(
                  hintText: 'What was it for?',
                ),
                style: TextStyle(fontSize: 22),
              ),
              SizedBox(
                height: 20.0,
              ),
              FlatButton(
                  onPressed: () {
                    if (_formKey.currentState.validate()) {
                      Scaffold.of(context).showSnackBar(SnackBar(
                          content: Text(
                        'Hang on a sec..',
                        style: TextStyle(fontSize: 22),
                      )));

                      // Submit to server
                      _submitGoogleForm().then((isSuccess) {
                        // Report result
                        Scaffold.of(context).showSnackBar(SnackBar(
                            content: Text(
                          isSuccess ? 'Success' : 'Failed',
                          style: TextStyle(fontSize: 22),
                        )));

                        // Hide Snackbar in use (if present)
                        Scaffold.of(context).hideCurrentSnackBar();

                        if (isSuccess) {
                          _clearForm();

                          // Focus on Amount
                          FocusScope.of(context).requestFocus(fcsNodeTxtAmount);
                        }
                      });
                    }
                  },
                  color: Colors.purple,
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text(
                      'Log it',
                      style: TextStyle(fontSize: 22.0, color: Colors.white),
                    ),
                  ))
            ],
          ),
        ),
      ),
    );
  }
}

How do I prevent it from scrolling back?

I've tried:

  • adding physics: ScrollPhysics() to the ListView (no change in behavior)
  • adding key: ObjectKey(_list.hashCode) to the ListView (no change in behavior)

Remove final _formKey = GlobalKey<FormState>(); from build method and make its as state variable.

class _FormScreenState extends State<FormScreen> {
  final _formKey = GlobalKey<FormState>();
  ...

  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: SafeArea(
        child: Container(
        ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM