Marcin Szałek
Marcin Szałek

Reputation: 5069

Flutter Listview in stateless widget with initial offset

I have my own StatelessWidget with a ListView. I want it's state to be managed by parent StatefulWidget.

The behaviour I desire is that if I change a value, listView scrolls (or even jumps - it doesn't matter) to that value.

I thought that if I create stateless widget every time parent's setState() method is being invoked, the scrollController with initialOffset would make the list "move" but it doesn't. What is worth mentioning is that on first build initialOffset works as it should.

Here is example code of my problem:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 5;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new MyClass(_counter),
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,
        child: new Icon(Icons.add),
      ),
    );
  }
}

class MyClass extends StatelessWidget {
  final int extraValue;
  final ScrollController scrollController;

  MyClass(this.extraValue):
  scrollController = new ScrollController(initialScrollOffset: extraValue*50.0);

  @override
  Widget build(BuildContext context) {
    return new ListView.builder(
        itemExtent: 50.0,
        itemCount: 100,
        controller: scrollController,
        itemBuilder: (BuildContext context, int index) {
      if (index != extraValue)
        return new Text(index.toString());
      else
        return new Text("EXTRA" + index.toString());
    });
  }
}

I'm not sure if it's a bug or my mistake.

Any ideas might be helpful :)

EDIT: Inspired by Ian Hickson's answer I have solution to my problem:

void _incrementCounter() {
    setState(() {
      _counter++;
      myClass.scrollController.animateTo(_counter*50.0, duration: new Duration(seconds: 1), curve: new ElasticOutCurve());
    });
  }

Upvotes: 0

Views: 3507

Answers (1)

Ian Hickson
Ian Hickson

Reputation: 8599

The initial offset is... the initial offset. Not the current offset. :-)

You can cause the offset to change by calling methods on the ScrollController, like animateTo.

Upvotes: 1

Related Questions