Flutter异常:ScrollController附加到多个滚动视图

我的Flutter应用程序从ScrollController要控制的页面离开时抛出了异常(将ScrollController附加到多个滚动视图)NestedScrollView,我不确定自己在做什么错。

我用下面的简单示例重新创建了异常。我可以从导航FirstPageSecondPage(也可以选择返回)就好了,但是当我从导航SecondPageThirdPage异常时,会引发异常。该SecondPage页面包含我CollapsingAppBarPage认为有问题的自定义窗口小部件。CollapsingAppBarPage在此示例中被简化了,但是在我的真实应用中,它会根据滚动位置更改组件的颜色/大小。在此示例中,当_scrollController.offset导航开始到时会在调用时发生异常ThirdPage。另外,我知道FirstPage和ThirdPage可以是Stateless而不是StatefulWidgets,但我想使其尽可能与我的应用程序一样。这是我充分工作的示例。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Flutter Demo',

home: FirstPage(),

);

}

}

class FirstPage extends StatefulWidget {

@override

_FirstPageState createState() => _FirstPageState();

}

class _FirstPageState extends State<FirstPage> {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text("First Page"),

),

body: Center(

child: RaisedButton(

child: Text("Navigate Next"),

onPressed: () async {

await Navigator.push(context,

MaterialPageRoute(builder: (context) => SecondPage())

);

},

),

),

);

}

}

class SecondPage extends StatefulWidget {

@override

_SecondPageState createState() => _SecondPageState();

}

class _SecondPageState extends State<SecondPage> {

@override

Widget build(BuildContext context) {

return Material(

child: CollapsingAppBarPage(

titleText: "Second Page",

bodyCreator: (context) {

return ListView(

children: <Widget>[

Center(

child: RaisedButton(

child: Text("Navigate Next"),

onPressed: () async {

await Navigator.push(context,

MaterialPageRoute(builder: (context) => ThirdPage())

);

},

),

)

],

);

},

),

);

}

}

class ThirdPage extends StatefulWidget {

@override

_ThirdPageState createState() => _ThirdPageState();

}

class _ThirdPageState extends State<ThirdPage> {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text("Third Page")

),

body: Container()

);

}

}

typedef CollapsingAppBarBodyCreator = Widget Function(BuildContext context);

class CollapsingAppBarPage extends StatefulWidget {

final String titleText;

final CollapsingAppBarBodyCreator bodyCreator;

CollapsingAppBarPage({

Key key,

this.titleText,

@required this.bodyCreator,

}) : super(key: key);

@override

_CollapsingAppBarPageState createState() => _CollapsingAppBarPageState();

}

class _CollapsingAppBarPageState extends State<CollapsingAppBarPage> {

static const _kExpandedHeight = 200.0;

ScrollController _scrollController;

@override

void initState() {

super.initState();

_scrollController = ScrollController()

..addListener(() {

setState(() {

// force a refresh so the app bar can be updated

});

});

}

@override

void dispose() {

_scrollController.dispose();

super.dispose();

}

@override

Widget build(BuildContext context) {

return NestedScrollView(

controller: _scrollController,

headerSliverBuilder: _createSliverAppBar,

body: widget.bodyCreator(context),

);

}

List<Widget> _createSliverAppBar(BuildContext context, bool innerBoxIsScrolled) {

// change the icon color as the page scrolls

var collapsePercent = _getAppBarCollapsePercent();

int rgb = ((1.0 - collapsePercent) * 255).round();

var color = Color.fromARGB(255, rgb, rgb, rgb);

return <Widget>[

SliverAppBar(

expandedHeight: _kExpandedHeight,

pinned: true,

iconTheme: IconThemeData(color: color),

title: Text(widget.titleText),

)

];

}

double _getAppBarCollapsePercent() {

if (!_scrollController.hasClients)

return 0.0;

return (_scrollController.offset / (_kExpandedHeight - kToolbarHeight)).clamp(0.0, 1.0);

}

}

这是该异常的截断的痕迹:

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════

flutter: The following assertion was thrown building Builder(dirty):

flutter: ScrollController attached to multiple scroll views.

flutter: 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 111 pos 12:

flutter: '_positions.length == 1'

flutter:

flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially

flutter: more information in this error message to help you determine and fix the underlying cause.

flutter: In either case, please report this assertion by filing a bug on GitHub:

flutter: https://github.com/flutter/flutter/issues/new?template=BUG.md

flutter:

flutter: When the exception was thrown, this was the stack:

flutter: #2 ScrollController.position (package:flutter/src/widgets/scroll_controller.dart:111:12)

flutter: #3 ScrollController.offset (package:flutter/src/widgets/scroll_controller.dart:118:24)

flutter: #4 _CollapsingAppBarPageState._getAppBarCollapsePercent (package:flutter_scroll_test/main.dart:160:31)

flutter: #5 _CollapsingAppBarPageState._createSliverAppBar (package:flutter_scroll_test/main.dart:142:27)

flutter: #6 NestedScrollView._buildSlivers (package:flutter/src/widgets/nested_scroll_view.dart:271:20)

flutter: #7 _NestedScrollViewState.build.<anonymous closure> (package:flutter/src/widgets/nested_scroll_view.dart:347:29)

flutter: #8 Builder.build (package:flutter/src/widgets/basic.dart:5736:41)

flutter: #9 StatelessElement.build (package:flutter/src/widgets/framework.dart:3774:28)

flutter: #10 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15)

回答:

不要_scrollController.offset直接使用推入路线,因为当您再次弹出时接近滚动时,显然会附加要获取的滚动位置

所以我们需要将其转移到一个状态

这是完整的修订代码。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

@override

Widget build(BuildContext context) {

return MaterialApp(

title: 'Flutter Demo',

home: FirstPage(),

);

}

}

class FirstPage extends StatefulWidget {

@override

_FirstPageState createState() => _FirstPageState();

}

class _FirstPageState extends State<FirstPage> {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text("First Page"),

),

body: Center(

child: RaisedButton(

child: Text("Navigate Next"),

onPressed: () async {

await Navigator.push(context,

MaterialPageRoute(builder: (context) => SecondPage())

);

},

),

),

);

}

}

class SecondPage extends StatefulWidget {

@override

_SecondPageState createState() => _SecondPageState();

}

class _SecondPageState extends State<SecondPage> {

@override

Widget build(BuildContext context) {

return Material(

child: CollapsingAppBarPage(

titleText: "Second Page",

bodyCreator: (context) {

return ListView(

children: <Widget>[

Center(

child: RaisedButton(

child: Text("Navigate Next"),

onPressed: () async {

await Navigator.push(context,

MaterialPageRoute(builder: (context) => ThirdPage())

);

},

),

)

],

);

},

),

);

}

}

class ThirdPage extends StatefulWidget {

@override

_ThirdPageState createState() => _ThirdPageState();

}

class _ThirdPageState extends State<ThirdPage> {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text("Third Page")

),

body: Container()

);

}

}

typedef CollapsingAppBarBodyCreator = Widget Function(BuildContext context);

class CollapsingAppBarPage extends StatefulWidget {

final String titleText;

final CollapsingAppBarBodyCreator bodyCreator;

CollapsingAppBarPage({

Key key,

this.titleText,

@required this.bodyCreator,

}) : super(key: key);

@override

_CollapsingAppBarPageState createState() => _CollapsingAppBarPageState();

}

class _CollapsingAppBarPageState extends State<CollapsingAppBarPage> {

static const _kExpandedHeight = 200.0;

ScrollController _scrollController;

//Offset state <-------------------------------------

double offset = 0.0 ;

@override

void initState() {

super.initState();

//print("init state is called");

_scrollController = ScrollController() //keepScrollOffset: false removed

..addListener(() {

setState(() {

//<-----------------------------

offset = _scrollController.offset;

// force a refresh so the app bar can be updated

});

});

}

@override

void dispose() {

_scrollController.dispose();

super.dispose();

}

@override

Widget build(BuildContext context) {

return NestedScrollView(

controller: _scrollController,

headerSliverBuilder: _createSliverAppBar,

body: widget.bodyCreator(context),

);

}

List<Widget> _createSliverAppBar(BuildContext context, bool innerBoxIsScrolled) {

// change the icon color as the page scrolls

print("_createSliverAppBar is called");

var collapsePercent = _getAppBarCollapsePercent();

int rgb = ((1.0 - collapsePercent) * 255).round();

var color = Color.fromARGB(255, rgb, rgb, rgb);

return <Widget>[

SliverAppBar(

expandedHeight: _kExpandedHeight,

pinned: true,

iconTheme: IconThemeData(color: color),

title: Text(widget.titleText),

)

];

}

double _getAppBarCollapsePercent() {

if (!_scrollController.hasClients ){

print("positions is ${_scrollController.positions.length}");

return 0.0;

}

//print("offset is${_scrollController.offset} and positions is ${_scrollController.positions.length}");

return (offset / (_kExpandedHeight - kToolbarHeight)).clamp(0.0, 1.0);

}

}

以上是 Flutter异常:ScrollController附加到多个滚动视图 的全部内容, 来源链接: utcz.com/qa/430241.html

回到顶部