【问题标题】:How to make ExpansionTile scrollable when end of screen is reached?到达屏幕末尾时如何使 ExpansionTile 可滚动?
【发布时间】:2022-01-10 13:48:00
【问题描述】:

在我目前正在进行的项目中,我有一个Scaffold,其中包含一个SinlgeChildScrollView。在这个SingleChildScrollView 中显示的是实际内容,允许在内容离开屏幕时进行滚动。

虽然这对我大约 90% 的屏幕有意义,但我有一个屏幕显示 2 ExpansionTiles。这两个都可能包含许多条目,展开后会变得非常大。

现在的问题是,我希望ExpansionTile 最迟在到达屏幕底部时停止扩展,并使ExpansionTile(即ListTiles)中的内容可滚动。

当前条目过多时屏幕是这样的:

如您所见,ExpansionTile 离开屏幕,迫使用户滚动实际屏幕,这将导致两个ExpansionTiles 的标题从屏幕上消失,因为列表中有足够的条目.即使从 Scaffold 中删除 SingleChildScrollView 也不能解决问题,只会导致 RenderOverflow

用于生成 Scaffold 及其内容的代码如下:

class MembershipScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MembershipScreenState();

}

class _MembershipScreenState extends State<MembershipScreen> {

  String _fontFamily = 'OpenSans';

  Widget _buildMyClubs() {
    return Container(
      decoration: BoxDecoration(
          color: Colors.white,
          border: Border.all(
              color: Color(0xFFD2D2D2),
              width: 2
          ),
          borderRadius: BorderRadius.circular(25)
      ),
      child: Theme(
        data: ThemeData().copyWith(dividerColor: Colors.transparent),
        child: ExpansionTile(
            title: Text("My Clubs"),
            trailing: Icon(Icons.add),
            children: getSearchResults(),
        ),
      )
    );
  }

  Widget _buildAllClubs() {
    return Container(
      decoration: BoxDecoration(
          color: Colors.white,
          border: Border.all(
              color: Color(0xFFD2D2D2),
              width: 2
          ),
          borderRadius: BorderRadius.circular(25)
      ),
      child: Theme(
        data: ThemeData().copyWith(dividerColor: Colors.transparent),
        child: SingleChildScrollView(
          child: ExpansionTile(
            title: Text("All Clubs"),
            trailing: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                Icon(Icons.add)
              ],
            ),
            children: getSearchResults(),
          ),
        )
      )
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBody: true,
      body: AnnotatedRegion<SystemUiOverlayStyle>(
          value: SystemUiOverlayStyle.light,
          child: GestureDetector(
            onTap: () => FocusScope.of(context).unfocus(),
            child: Stack(
              children: <Widget>[
                Container(
                  height: double.infinity,
                  width: double.infinity,
                  decoration: BoxDecoration(
                      gradient: kGradient //just some gradient
                  ),
                ),
                Center(
                  child: Container(
                  height: double.infinity,
                  constraints: BoxConstraints(maxWidth: 500),
                  child: SingleChildScrollView(
                      physics: AlwaysScrollableScrollPhysics(),
                      padding: EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          Text(
                            'Clubs',
                            style: TextStyle(
                                fontSize: 30.0,
                                color: Colors.white,
                                fontFamily: _fontFamily,
                                fontWeight: FontWeight.bold),
                          ),
                          SizedBox(
                            height: 20,
                          ),
                          _buildMyClubs(),
                          SizedBox(height: 20,),
                          _buildAllClubs()
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            ),
          )
      ),
    );
  }

  List<Widget> getSearchResults() {
    return [
      ListTile(
        title: Text("Test1"),
        onTap: () => print("Test1"),
      ),
      ListTile(
        title: Text("Test2"),
        onTap: () => print("Test2"),
      ), //etc..
    ];
  }

}

我希望我没有通过删除不相关的部分来破坏代码,以便在将其发布到此处之前减小大小。希望有人知道如何实现我打算在这里做的事情,并且可以帮助我解决这个问题。

编辑

由于我尝试实现的目标可能不容易理解,因此我尝试为所需行为提出可视化:

因此,用虚线包围的项目包含在列表中,但无法显示,因为它们会超出视口的边界。因此,包含该项目的ExpansionTile 需要提供一个滚动条供用户在列表中向下滚动。因此,ExpansionTiles 始终可见。

【问题讨论】:

    标签: flutter scrollable singlechildscrollview


    【解决方案1】:

    试试下面的代码希望它对你有帮助。在Column()Column() 中添加您的ExpansionTile() 小部件,并在SingleChildScrollView() 中换行

    1. 参考 SingleChildScrollView here
    2. 参考专栏here
    3. 您也可以参考我的回答 here 对于 ExpansionPanel
    4. 参考列表here
    5. 参考 ListView.builder() here

    你的名单:

      List<Widget> getSearchResults = [
        ListTile(
          title: Text("Test1"),
          onTap: () => print("Test1"),
        ),
        ListTile(
          title: Text("Test2"),
          onTap: () => print("Test2"),
        ), //etc..
      ];
    

    您的小部件使用ListView.builder():

    SingleChildScrollView(
        padding: EdgeInsets.all(20),
        child: Column(
          children: [
            Card(
              child: ExpansionTile(
                title: Text(
                  "My Clubs",
                ),
                trailing: Icon(
                  Icons.add,
                ),
                children: [
                  ListView.builder(
                    shrinkWrap: true,
                    itemBuilder: (BuildContext context, int index) {
                      return Column(
                        children: getSearchResults,
                      );
                    },
                    itemCount: getSearchResults.length, // try 50 length just testing
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    

    您的简单小部件:

     SingleChildScrollView(
        padding: EdgeInsets.all(20),
        child: Column(
          children: [
            Card(
              child: ExpansionTile(
                title: Text(
                  "My Clubs",
                ),
                trailing: Icon(
                  Icons.add,
                ),
                children:getSearchResults
                 
              ),
            ),
          ],
        ),
      ),
    

    您的结果屏幕 ->

    【讨论】:

    • 感谢您的建议,但似乎并不能完全解决实际问题。如果我像这样实现它,我会像以前一样得到列表,这次包裹在 Card 中,但列表本身对我来说仍然不可滚动,并且包含结果的列表仍然延伸到屏幕边框之外。顺便说一句,我使用ListView.builder 使用了您建议的解决方案。同样在任何情况下,是否有一种可能的解决方案是使用 Container 而不是 Card 小部件来保留应用程序的 LnF?
    • @Samaranth 是的,您可以使用Container 而不是Card,并且您使用了ListView.Builder 并且列表不可滚动只需在Listview.builder 中添加physics: NeverScrollableScrollPhysics(), 参考NeverScrollableScrollPhysics here 希望它对你有帮助。
    • 我实际上尝试了如何使用NeverScrollableScrollPhysics()AlwaysScrollableScrollPhysics() 改变了与小部件的交互,但无论如何它并没有改变小部件本身不可滚动但只有围绕它的脚手架这一事实.但很高兴知道您对 Card 的建议很容易替换为 Container
    • @Samaranth 你的问题解决了吗?
    • 不,不是。主要问题是ExpansionTile 本身是不可滚动的,并且当它包含足够的条目时会扩展到屏幕边框之外。目前唯一的可能性是向下滚动主视图,这不是应该的。我寻找一种解决方案,使ExpansionTile 略高于BottomNavBar,并且我可以将ExpansionTile 中包含的所有元素作为可滚动列表滚动。 IE。上部和下部的 ExpansionTiles 以及它们的标题“My Clubs”和“All Clubs”始终都是可见的。
    猜你喜欢
    • 1970-01-01
    • 2016-11-04
    • 2018-06-04
    • 1970-01-01
    • 2021-02-06
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    • 2012-05-05
    相关资源
    最近更新 更多