4

I make error when using animateToPage

ScrollController attached to multiple scroll views. 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 109 pos 12: '_positions.length == 1'

I try to use _pageController.hasClients but it not working.

Please have a look in my code-

import 'package:flutter/material.dart';

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

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

  @override
  _MyAppState createState() =>_MyAppState();
}

class _MyAppState extends State {
  PageController _pageController;
  ScrollController _scrollController;
  double offset = 0.0;

  @override
  void initState(){
    super.initState();
    _pageController = PageController(initialPage: 0);
    _scrollController = ScrollController();
    _scrollController.addListener(this.swapPageListener);
  }

  void swapPageListener() {
    offset = _scrollController.offset;
    _pageController.hasClients
    if (offset > _scrollController.position.maxScrollExtent + 100) {
      _pageController.animateToPage(1, duration: Duration(milliseconds: 500), curve: Curves.ease);
    }
    if (offset < _scrollController.position.minScrollExtent - 100) {
      _pageController.animateToPage(0, duration: Duration(milliseconds: 500), curve: Curves.ease);
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: PageView.builder(
            controller: _pageController,
            scrollDirection: Axis.vertical,
            itemCount: 2,
            physics: PageScrollPhysics(),
            itemBuilder: (context, idx) {
              if(idx == 0) {
                return _screen1();
              } else {
                return _screen2();
              }
            }
        ),
      ),
    );
  }

  Widget _screen1() {
    return SingleChildScrollView(
      physics: BouncingScrollPhysics(),
      controller: _scrollController,
      child: Container(
        height: 1000.0,
        color: Colors.red,
        child: Center(
          child: Text('screen 1'),
        ),
      ),
    );
  }

  Widget _screen2() {
    return SingleChildScrollView(
      physics: BouncingScrollPhysics(),
      controller: _scrollController,
      child: Container(
        height: 1000.0,
        color: Colors.green,
        child: Center(
          child: Text('screen 2'),
        ),
      ),
    );
  }
}

Thanks in advance

Hello, I have found the solution to this problem

import 'package:flutter/material.dart';

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

PageController _pageController;

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

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  void initState(){
    super.initState();
    _pageController = PageController(initialPage: 0);
  }


  // @override
  // void dispose() {
  //   super.dispose();
  //   _pageController.dispose();
  // }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: PageView.builder(
          controller: _pageController,
          scrollDirection: Axis.vertical,
          itemCount: 2,
          physics: NeverScrollableScrollPhysics(),
          itemBuilder: (context, idx) {
            return Screen(pageKey: idx,);
          }
        ),
      ),
    );
  }
}

class Screen extends StatefulWidget {
  Screen({Key key, this.pageKey}) : super(key: key);
  final pageKey;

  @override
  _ScreenState createState() => _ScreenState();
}

class _ScreenState extends State<Screen> {
  ScrollController _scrollController;

  @override
  void initState(){
    super.initState();
    _scrollController = ScrollController();
    _scrollController.addListener(this.swapPageListener);
  }

  void swapPageListener() {
    if (_scrollController.offset > _scrollController.position.maxScrollExtent + 100) {
      _pageController.animateToPage(1, duration: Duration(milliseconds: 400), curve: Curves.easeInOut);
    }
    if (_scrollController.offset < _scrollController.position.minScrollExtent - 100) {
      _pageController.animateToPage(0, duration: Duration(milliseconds: 400), curve: Curves.easeInOut);
    }
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      physics: BouncingScrollPhysics(),
      controller: _scrollController,
      child: Container(
        height: 1000.0,
        color: Colors.green,
        child: Center(
          child: Text('screen ${widget.pageKey}'),
        ),
      ),
    );
  }
}

2 Answers 2

2

please check out your solution

import 'package:flutter/material.dart';

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

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

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State {
  PageController _pageController;
  ScrollController _scrollController;
  double offset = 0.0;

  @override
  void initState(){
    super.initState();
    _pageController = PageController(initialPage: 0);
    _scrollController = ScrollController();
    _scrollController.addListener(this.swapPageListener);

  }

  void swapPageListener() {

    offset = _scrollController.offset;
    setState(() {
      _pageController.hasClients;
      if (offset > _scrollController.position.maxScrollExtent + 100) {
        _pageController.animateToPage(1, duration: Duration(milliseconds: 500), curve: Curves.ease);
      }
      if (offset <_scrollController.position.minScrollExtent - 100) {
        _pageController.animateToPage(0, duration: Duration(milliseconds: 500), curve: Curves.ease);
      }
    });

  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: PageView.builder(
            controller: _pageController,
            scrollDirection: Axis.vertical,
            pageSnapping: true,
            itemCount: 2,
            physics: PageScrollPhysics(),
            itemBuilder: (context, idx) {
              if(idx == 0) {
                return _screen1();
              } else {
                return _screen2();
              }
            }
        ),
      ),
    );
  }

  Widget _screen1() {
    return SingleChildScrollView(
      physics: BouncingScrollPhysics(),
      controller: _scrollController,
      child: Container(
        height: 1000.0,
        color: Colors.red,
        child: Center(
          child: Text('screen 1'),
        ),
      ),
    );
  }

  Widget _screen2() {
    return SingleChildScrollView(
      physics: BouncingScrollPhysics(),
      controller: _scrollController,
      child: Container(
        height: 1000.0,
        color: Colors.green,
        child: Center(
          child: Text('screen 2'),
        ),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

12 Comments

I tried your code and it still got the error.
copy my code and paste it I hope working. In my pc, it worked
yes it works but it will still return an error
please uninstall your previous app and re-run it, from my end I have found no error
And have look in your swapPageListener() method and wrap your code in set state
|
0

In my case I reuse a same PageView in several pages, and whenever I called .animateToPage(), it showed the error, and the mistake I did is simple.

Mistake:

static final PageController _pageController = PageController();

Fix:

late PageController _pageController;

 @override
  void initState() {
     _pageController = PageController();
...

Here I just initialized new controllers for each page, which calls this common page view widget when it's initialized. The same applies for the ScrollControllers depend on your case.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.