代码之家  ›  专栏  ›  技术社区  ›  Renato Stauffer

颤振:ListView不可滚动,不反弹

  •  31
  • Renato Stauffer  · 技术社区  · 6 年前

    我有以下示例(在iPhone X、iOS 11上测试):

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @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> {
    
      @override
      Widget build(BuildContext context) {
        return new ListView(
          children: <Widget>[
            new Container(
              height: 40.0,
              color: Colors.blue,
            ),
            new Container(
              height: 40.0,
              color: Colors.red,
            ),
            new Container(
              height: 40.0,
              color: Colors.green,
            ),
          ]
        );
      }
    
    }
    

    在这种情况下,ListView的行为与预期的一样。我可以滚动到视口之外,ListView会再次反弹(典型的iOS行为)。但当我添加ScrollController来跟踪偏移量时,滚动的行为会发生变化:

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @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> {
      ScrollController _controller = new ScrollController();
    
      @override
      Widget build(BuildContext context) {
        return new ListView(
          controller: _controller,
          children: <Widget>[
            new Container(
              height: 40.0,
              color: Colors.blue,
            ),
            new Container(
              height: 40.0,
              color: Colors.red,
            ),
            new Container(
              height: 40.0,
              color: Colors.green,
            ),
          ]
        );
      }
    }
    

    在这种情况下,无法再滚动。为什么当我添加ScrollController时,滚动就不可能了?同时添加 physics: new BouncingScrollPhysics(), 到ListView没有帮助。

    感谢您的帮助:)

    8 回复  |  直到 6 年前
        1
  •  32
  •   Fabio Veronese    6 年前

    始终在上启用滚动 ListView 您可以使用 AlwaysScrollableScrollPhysics 班更多详细信息 here . 如果需要,可以指定 parent 或者依赖默认值。

    以下是添加选项的示例:

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @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> {
      ScrollController _controller = new ScrollController();
    
      @override
      Widget build(BuildContext context) {
        return new ListView(
            physics: const AlwaysScrollableScrollPhysics(), // new
            controller: _controller,
            children: <Widget>[
              new Container(
                height: 40.0,
                color: Colors.blue,
              ),
              new Container(
                height: 40.0,
                color: Colors.red,
              ),
              new Container(
                height: 40.0,
                color: Colors.green,
              ),
            ]
        );
      }
    }
    
        2
  •  12
  •   Kamal Bunkar    3 年前

    如果您在Flatter Web上遇到这个问题,那么您应该将listview包装为 滚动配置 . 添加PointerDeviceKind。ScrollConfiguration行为参数中的鼠标。 You can see example .

    ScrollConfiguration(
    behavior: ScrollConfiguration.of(context).copyWith(dragDevices: {
      PointerDeviceKind.touch,
      PointerDeviceKind.mouse,
    },),
    child: ListView(
      controller: _controller,
      physics: const AlwaysScrollableScrollPhysics(),
      scrollDirection: Axis.horizontal,
      children: <Widget>[
      
          for (int index = 0; index < showThumbnailList.length; index++) _thumbnail(showThumbnailList[index], index)
       
        // showThumbnailList.map((x) => _thumbnail(x) ).toList()),
      ],
    ),
    

    ),

        3
  •  5
  •   CopsOnRoad    4 年前

    只需添加 AlwaysScrollableScrollPhysics

    ListView(
            physics: const AlwaysScrollableScrollPhysics(),
            children :  [...]
    }
    
        4
  •  1
  •   ken    5 年前

    我认为没有CustomScrollView这个解决方案更好。只需使用NotificationListener包装ListView。

      Widget noti = new NotificationListener(
        child:listView,
        onNotification: (ScrollNotification note){
          print(note.metrics.pixels.toInt());
        },
      );
    

    我已经测试过了,弹跳是有效的

        5
  •  1
  •   Rasel Khan    4 年前

    **

    使用容器高度进行滚动,并使用 物理:AlwaysScrollableScrollPhysics(), 控制器:控制器,

    **

    Container(
        width: 400,
        child: Drawer(
          child: Stack(children: [
            Container(
              height: MediaQuery.of(context).size.height-80,
              child: ListView(
                controller: controller,
                padding: EdgeInsets.zero,
                
                physics: AlwaysScrollableScrollPhysics(),
                children: [
                  Container(
                    height: 300,
                    padding: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
                    child: DrawerHeader(
                      child:Stack(children: [
                        Center(
                          child: Column(
                            children: [
                              nullCatcher(image) == "" ? Image.asset("assets/images/doctor.png",height: 90,width: 90,) : Image.network(
                                "$image",
                                height: 90,
                                width: 90,
                              ),
                              SizedBox(width: 30,),
                              Text("$name",style: TextStyle(color: Colors.grey[700],fontWeight: FontWeight.bold,fontSize: 25),),
                              Text("$specialty",style: TextStyle(color: Colors.grey[600]),),
                            ],
                          ),
                        ),
                        Positioned(
                            right: 0,bottom: 10,
                            child: Text("Version: 1.0.0",style: TextStyle(color: Colors.orange),))
                      ],),
    
                    ),
                  ),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: Container(
                        height: 70,
                        padding: EdgeInsets.symmetric(horizontal: 30),
                        decoration: drawerListDecoration,
                        child: Row(
                          children: [
                            Container(
                                height: 35,width: 35,
                                decoration: BoxDecoration(
                                    color: Theme.of(context).accentColor,
                                    borderRadius: BorderRadius.circular(100)
                                ),
                                child: Icon(Icons.attach_file,color: Colors.white,size: 20,)),
                            SizedBox(width: 20,),
                            Text('Create Appointment'),
                          ],
                        )),
                    onTap: () {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (__)=>CreateAppointment()));
                      // Update the state of the app.
                      // ...
                    },
                  ),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: Container(
                        height: 70,
                        padding: EdgeInsets.symmetric(horizontal: 30),
                        decoration: drawerListDecoration,
                        child: Row(
                          children: [
                            Container(
                                height: 35,width: 35,
                                decoration: BoxDecoration(
                                    color: Theme.of(context).accentColor,
                                    borderRadius: BorderRadius.circular(100)
                                ),
                                child: Icon(Icons.attach_file,color: Colors.white,size: 20,)),
                            SizedBox(width: 20,),
                            Text('Appointment / Prescription List'),
                          ],
                        )),
                    onTap: () {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (__)=>AppointmentList()));
                      // Navigator.pop(context);
                    },
                  ),
                  Container(
                    height: 70,
                    padding: EdgeInsets.symmetric(horizontal: 30 ),
                    color: Colors.grey[200],
                    child: Row(
                      children: [
                        Container(
                            height: 35,width: 35,
                            decoration: BoxDecoration(
                                color: Theme.of(context).accentColor,
                                borderRadius: BorderRadius.circular(100)
                            ),
                            child: Icon(Icons.attach_file,color: Colors.white,size: 20,)),
                        SizedBox(width: 20,),
                        Text("Clinical Options:",style: TextStyle(fontWeight: FontWeight.bold,color: Colors.grey[600]),),
                      ],
                    ),
                  ),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: Container(
                        height: childHeight,
                        padding: EdgeInsets.only(left: childPaddeing),
                        // decoration: drawerListDecoration,
                        child: Row(
                          children: [
                            lineDesign(),
                            SizedBox(width: 20,),
                            Text('Chief Complain'),
                          ],
                        )),
                    onTap: () {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (__)=>AppointmentList()));
                      // Navigator.pop(context);
                    },
                  ),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: Container(
                        height: 50,
                        padding: EdgeInsets.symmetric(horizontal: 45),
                        decoration: drawerListDecoration,
                        child: Row(
                          children: [
                            lineDesign(),
                            SizedBox(width: 20,),
                            Text('On Examination'),
                          ],
                        )),
                    onTap: () {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (__)=>AppointmentList()));
                      // Navigator.pop(context);
                    },
                  ),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: Container(
                        height: 70,
                        padding: EdgeInsets.symmetric(horizontal: 30),
                        decoration: drawerListDecoration,
                        child: Row(
                          children: [
                            Container(
                                height: 35,width: 35,
                                decoration: BoxDecoration(
                                    color: Theme.of(context).accentColor,
                                    borderRadius: BorderRadius.circular(100)
                                ),
                                child: Icon(Icons.attach_file,color: Colors.white,size: 20,)),
                            SizedBox(width: 20,),
                            Text('Examination Category'),
                          ],
                        )),
                    onTap: () {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (__)=>AppointmentList()));
                      // Navigator.pop(context);
                    },
                  ),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: Container(
                        height: 70,
                        padding: EdgeInsets.symmetric(horizontal: 30),
                        decoration: drawerListDecoration,
                        child: Row(
                          children: [
                            Container(
                                height: 35,width: 35,
                                decoration: BoxDecoration(
                                    color: Theme.of(context).accentColor,
                                    borderRadius: BorderRadius.circular(100)
                                ),
                                child: Icon(Icons.attach_file,color: Colors.white,size: 20,)),
                            SizedBox(width: 20,),
                            Text('Diagnosis'),
                          ],
                        )),
                    onTap: () {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (__)=>AppointmentList()));
                      // Navigator.pop(context);
                    },
                  ),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: Container(
                        height: 70,
                        padding: EdgeInsets.symmetric(horizontal: 30),
                        decoration: drawerListDecoration,
                        child: Row(
                          children: [
                            Container(
                                height: 35,width: 35,
                                decoration: BoxDecoration(
                                    color: Theme.of(context).accentColor,
                                    borderRadius: BorderRadius.circular(100)
                                ),
                                child: Icon(Icons.attach_file,color: Colors.white,size: 20,)),
                            SizedBox(width: 20,),
                            Text('Investigations'),
                          ],
                        )),
                    onTap: () {
                      Navigator.pushReplacement(context, MaterialPageRoute(builder: (__)=>AppointmentList()));
                      // Navigator.pop(context);
                    },
                  ),
    
                ],
              ),
            ),
            Positioned(
                bottom: 0,
                left: 0,
                right: 0,
                child: ButtonTheme(
                  child: RaisedButton(
                    color: Colors.red[900],
                    onPressed: (){
                      if(blocState is LogoutInLoading){}else logoutAlert(blocContext);
                    },
                    child: Container(
                      height: 70,
                      child:blocState is LogoutInLoading ? Container( height: 20,width: 20,margin: EdgeInsets.symmetric(vertical: 25), child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Colors.white),),) : Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Text("Sign Out",style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 25),),
                          SizedBox(width: 20,),
                          Icon(Icons.logout,color: Colors.white,)
                        ],
                      ),
                    ),
                  ),
                )
            )
          ],),
        ),
      );
    
        6
  •  0
  •   Renato Stauffer    5 年前

    我找到了一个解决方案,如何使用内容高度小于视口的列表跟踪偏移。使用 NotificationListener 连同 CustomScrollView build() 方法如下:

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @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> {
      ScrollController _controller = new ScrollController();
    
      @override
      Widget build(BuildContext context) {
        return new NotificationListener(
          onNotification: _handleScrollPosition,
            child: new CustomScrollView(
                slivers: [
                  new SliverList(
                      delegate: new SliverChildListDelegate([
                        new Container(
                          height: 40.0,
                          color: Colors.blue,
                        ),
                        new Container(
                          height: 40.0,
                          color: Colors.red,
                        ),
                        new Container(
                          height: 40.0,
                          color: Colors.green,
                        ),
                      ])
                  )
                ]
            )
        );
      }
    
      bool _handleScrollPosition(ScrollNotification notification) {
        print(notification.metrics.pixels);
        return true;
      }
    }
    

    只要没有解决方案 ScrollController 只有(或“更好”(更优雅)的解决方案,我才会接受这个答案。

        7
  •  0
  •   saeedmpt    2 年前

    在macOs中

    class MyCustomScrollBehavior extends MaterialScrollBehavior {
      // Override behavior methods and getters like dragDevices
      @override
      Set<PointerDeviceKind> get dragDevices => { 
        PointerDeviceKind.touch,
        PointerDeviceKind.mouse,
        // etc.
      };
    }
    
    // Set ScrollBehavior for an entire application.
    MaterialApp(
      scrollBehavior: MyCustomScrollBehavior(),
      // ...
    );
    
        8
  •  0
  •   BlackPearl    2 年前

    在我的例子中,我只是向父容器添加了一个指定的高度,如下所示

    sizedBox(
     height:300
     child:   child: ListView.builder(
              controller: _controller,
              physics: const AlwaysScrollableScrollPhysics(),
              shrinkWrap: true,
              itemCount: news.length,
              itemBuilder: (context, index) {
                //container
              }
    
    )