You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter嵌套滚动组件报错:Bad state: Too many elements

解决嵌套滚动组件的"Bad state: Too many elements"异常

问题场景

UI层级为 SlidingUpPanel > PageView > 2个CustomScrollView,功能运行正常,但日志频繁抛出大量Bad state: Too many elements异常。

问题原因

同一个ScrollController被同时绑定给外层的SlidingUpPanel以及PageView内的两个CustomScrollView,多个滚动组件共享同一控制器时,Flutter内部的滚动状态管理会出现冲突,触发异常。

解决方案

仅将共享的ScrollController绑定到PageView的当前活跃页面,非活跃页面使用独立的ScrollController,避免多组件共享同一控制器引发的状态冲突。

修改后的代码

import 'package:flutter/material.dart';
import 'package:sliding_up_panel2/sliding_up_panel2.dart';
import 'package:flutter/services.dart';
import 'package:flutter_map/flutter_map.dart';

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

class SlidingUpPanelExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
      systemNavigationBarColor: Colors.grey[200],
      systemNavigationBarIconBrightness: Brightness.dark,
      systemNavigationBarDividerColor: Colors.black,
    ));

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'SlidingUpPanel Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double _panelHeightOpen = 0;
  final double _panelHeightClosed = 95.0;
  late ScrollController sharedScrollController;
  late PanelController panelController;
  late PageController pageController;
  int currentPage = 0;
  // 为非活跃页面准备独立控制器
  final ScrollController _page0ScrollController = ScrollController();
  final ScrollController _page1ScrollController = ScrollController();

  @override
  void initState() {
    sharedScrollController = ScrollController();
    panelController = PanelController();
    pageController = PageController();
    // 监听页面切换,更新当前活跃页面索引
    pageController.addListener(() {
      setState(() {
        currentPage = pageController.page?.round() ?? 0;
      });
    });
    super.initState();
  }

  @override
  void dispose() {
    sharedScrollController.dispose();
    panelController.dispose();
    pageController.dispose();
    _page0ScrollController.dispose();
    _page1ScrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    _panelHeightOpen = MediaQuery.of(context).size.height * .80;

    return Material(
      child: Stack(
        alignment: Alignment.topCenter,
        children: <Widget>[
          SlidingUpPanel(
            controller: panelController,
            scrollController: sharedScrollController,
            maxHeight: _panelHeightOpen,
            minHeight: _panelHeightClosed,
            parallaxEnabled: true,
            parallaxOffset: .5,
            body: _body(),
            panelBuilder: () => _panel(),
            borderRadius: const BorderRadius.only(
                topLeft: Radius.circular(18.0),
                topRight: Radius.circular(18.0)),
          ),
          // SlidingUpPanel 标题
          Positioned(
            top: 52.0,
            child: Container(
              padding: const EdgeInsets.fromLTRB(24.0, 18.0, 24.0, 18.0),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(24.0),
                boxShadow: const [
                  BoxShadow(
                      color: Color.fromRGBO(0, 0, 0, .25), blurRadius: 16.0)
                ],
              ),
              child: const Text(
                "SlidingUpPanel Example",
                style: TextStyle(fontWeight: FontWeight.w500),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _panel() {
    return MediaQuery.removePadding(
        context: context,
        removeTop: true,
        child: PageView(
          controller: pageController,
          children: [
            createCustomScrollView(0),
            createCustomScrollView(1),
          ],
        ));
  }

  CustomScrollView createCustomScrollView(int index) {
    var cityName = index == 0 ? "Pittsburgh" : "Boston";
    // 仅当前活跃页面使用共享控制器
    ScrollController targetController = index == currentPage 
        ? sharedScrollController 
        : (index == 0 ? _page0ScrollController : _page1ScrollController);
    
    return CustomScrollView(
      controller: targetController,
      slivers: [
        SliverList(
            delegate: SliverChildListDelegate(<Widget>[
          _vertSpacer(12.0),
          _panelHandle(),
          _vertSpacer(18.0),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                cityName,
                style: const TextStyle(
                  fontWeight: FontWeight.normal,
                  fontSize: 24.0,
                ),
              ),
            ],
          ),
          _vertSpacer(36.0),
          Container(
            padding: const EdgeInsets.only(left: 24.0, right: 24.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                const Text("About",
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                    )),
                const SizedBox(
                  height: 12.0,
                ),
                Text(
                  """
                  $cityName is a city in the state of Pennsylvania in the United States, and is the county seat of Allegheny County. A population of about 302,407 (2018) residents live within the city limits, making it the 66th-largest city in the U.S. The metropolitan population of 2,324,743 is the largest in both the Ohio Valley and Appalachia, the second-largest in Pennsylvania (behind Philadelphia), and the 27th-largest in the U.S.\n$cityName is located in the southwest of the state, at the confluence of the Allegheny, Monongahela, and Ohio rivers. Pittsburgh is known both as "the Steel City" for its more than 300 steel-related businesses and as the "City of Bridges" for its 446 bridges. The city features 30 skyscrapers, two inclined railways, a pre-revolutionary fortification and the Point State Park at the confluence of the rivers. The city developed as a vital link of the Atlantic coast and Midwest, as the mineral-rich Allegheny Mountains made the area coveted by the French and British empires, Virginians, Whiskey Rebels, and Civil War raiders.\n\nAside from steel, Pittsburgh has led in manufacturing of aluminum, glass, shipbuilding, petroleum, foods, sports, transportation, computing, autos, and electronics. For part of the 20th century, Pittsburgh was behind only New York City and Chicago in corporate headquarters employment; it had the most U.S. stockholders per capita. Deindustrialization in the 1970s and 80s laid off area blue-collar workers as steel and other heavy industries declined, and thousands of downtown white-collar workers also lost jobs when several Pittsburgh-based companies moved out. The population dropped from a peak of 675,000 in 1950 to 370,000 in 1990. However, this rich industrial history left the area with renowned museums, medical centers, parks, research centers, and a diverse cultural district.\n\nAfter the deindustrialization of the mid-20th century, Pittsburgh has transformed into a hub for the health care, education, and technology industries. Pittsburgh is a leader in the health care sector as the home to large medical providers such as University of Pittsburgh Medical Center (UPMC). The area is home to 68 colleges and universities, including research and development leaders Carnegie Mellon University and the University of Pittsburgh. Google, Apple Inc., Bosch, Facebook, Uber, Nokia, Autodesk, Amazon, Microsoft and IBM are among 1,600 technology firms generating \$20.7 billion in annual Pittsburgh payrolls. The area has served as the long-time federal agency headquarters for cyber defense, software engineering, robotics, energy research and the nuclear navy. The nation's eighth-largest bank, eight Fortune 500 companies, and six of the top 300 U.S. law firms make their global headquarters in the area, while RAND Corporation (RAND), BNY Mellon, Nova, FedEx, Bayer, and the National Institute for Occupational Safety and Health (NIOSH) have regional bases that helped $cityName become the sixth-best area for U.S. job growth.
                  """,
                  softWrap: true,
                ),
              ],
            ),
          ),
          const SizedBox(
            height: 24,
          ),
        ]))
      ],
    );
  }

  SizedBox _vertSpacer(double height) {
    return SizedBox(
      height: height,
    );
  }

  Row _panelHandle() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Container(
          width: 30,
          height: 5,
          decoration: BoxDecoration(
              color: Colors.grey[300],
              borderRadius: const BorderRadius.all(Radius.circular(12.0))),
        ),
      ],
    );
  }

  Widget _body() {
    return FlutterMap(
      options: MapOptions(
        zoom: 13,
        maxZoom: 15,
      ),
      children: [
        TileLayer(
            urlTemplate: "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png"),
      ],
    );
  }
}

核心修改说明

  • 新增PageController监听页面切换,实时更新当前活跃页面索引
  • 为两个CustomScrollView分别创建独立控制器,仅当前活跃页面使用与SlidingUpPanel共享的控制器
  • 所有控制器在页面销毁时统一释放,避免内存泄漏

内容的提问来源于stack exchange,提问作者Jim G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 00:32:42