【问题标题】:how to create horizontal and vertical scrollable widgets in flutter如何在颤动中创建水平和垂直可滚动的小部件
【发布时间】:2018-11-18 20:43:48
【问题描述】:

示例布局图片

我正在尝试创建附加布局。它有两个容器。

  • 首先是一个固定大小的水平滚动框。
  • 第二个是占用剩余空间的卡片,里面有列表视图。

我怎样才能实现这种布局?

如您所见,两个容器的滚动方向不同。

代码在标签视图(第一个框)之前一直有效,但是当我添加第二个框(即卡)时,它没有显示任何内容并在控制台出现错误,如下所示..

I/flutter ( 9412):   AnimatedDefaultTextStyle ← _InkFeatures-[GlobalKey#85877 ink renderer] ←
I/flutter ( 9412):   NotificationListener<LayoutChangedNotification> ← ⋯
I/flutter ( 9412):   parentData: offset=Offset(0.0, 0.0); flex=null; fit=null (can use size)
I/flutter ( 9412):   constraints: BoxConstraints(0.0<=w<=340.0, 0.0<=h<=Infinity)
I/flutter ( 9412):   size: MISSING
I/flutter ( 9412):   additionalConstraints: BoxConstraints(biggest)
I/flutter ( 9412): This RenderObject had the following descendants (showing up to depth 5):
I/flutter ( 9412):   RenderFlex#93e12 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412):     RenderRepaintBoundary#977a7 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412):       RenderCustomPaint#b6be8 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412):         RenderRepaintBoundary#e449b NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 9412):           _RenderExcludableScrollSemantics#293fd NEEDS-LAYOUT NEEDS-PAINT



class _KanbanState extends State<Kanban> {
  @override
  Widget build(BuildContext context) {

    Widget tagList = 
    new SizedBox(
      height: 100.0,
      child: 
    new Column(
      children: <Widget>[
        new Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            new ActionChip(
                backgroundColor: Colors.yellow,
                label: new Text('Tag1'),
                onPressed: () {
                  // update board with selection
                }),
            new ActionChip(
                //backgroundColor: Colors.transparent,
                label: new Text('Tag2'),
                onPressed: () {
                  // update board with selection
                }),
            new ActionChip(
                label: new Text('Tag3'),
                onPressed: () {
                  // update board with selection
                }),
            new ActionChip(
                label: new Text('Tag4'),
                onPressed: () {
                  // update board with selection
                }),
          ],
        )
      ],
    ),);

    Widget boardView = new Flexible(
      // margin: new EdgeInsets.symmetric(vertical: 15.0),
      child: new Column(
        children: <Widget>[
          new ListView.builder(
            scrollDirection: Axis.vertical,
            itemCount: 5,
            itemBuilder: (BuildContext context, int index) {
              return new ListTile(
                onTap: () {
                },
                title: new Row(
                  children: <Widget>[
                    new Expanded(child: new Text("This is item name")),
                    new Text("12 Dec 18"),
                  ],
                ),
              );
            },
          ),
        ],
      ),
    );

    //  int _value=0;
    return new Container(
        child: new Scaffold(
          appBar: new AppBar(
            elevation: 1.0,
            title: new Text("Test title"),
          ),
          body: new Container(
              margin: new EdgeInsets.all(10.0),
              child: Column(
                children: <Widget>[
                  tagList,
                  boardView,
                ],
              )),
        ));
  }
}

【问题讨论】:

    标签: flutter flutter-layout


    【解决方案1】:

    tl;dr: 下面的代码做你想做的事 =D

    import 'package:flutter/material.dart';
    
    void main() async {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'stack overflow',
          theme: ThemeData(
            primarySwatch: Colors.pink,
          ),
          routes: {},
          home: KanbanState(),
        );
      }
    }
    
    class KanbanState extends StatefulWidget {
      @override
      KanbanStateState createState() {
        return KanbanStateState();
      }
    }
    
    class KanbanStateState extends State<KanbanState> {
      @override
      Widget build(BuildContext context) {
        Widget tagList = Container(
          color: Colors.green,
          height: 100.0,
          child: ListView(
            scrollDirection: Axis.horizontal,
            children: <Widget>[
              Row(
                children: <Widget>[
                  ActionChip(
                      backgroundColor: Colors.yellow,
                      label: Text('Tag1'),
                      onPressed: () {
                        // update board with selection
                      }),
                  ActionChip(
                      //backgroundColor: Colors.transparent,
                      label: Text('Tag2'),
                      onPressed: () {
                        // update board with selection
                      }),
                  ActionChip(
                      label: Text('Tag3'),
                      onPressed: () {
                        // update board with selection
                      }),
                  ActionChip(
                      label: Text('Tag4'),
                      onPressed: () {
                        // update board with selection
                      }),
                  ActionChip(
                      backgroundColor: Colors.yellow,
                      label: Text('Tag1'),
                      onPressed: () {
                        // update board with selection
                      }),
                  ActionChip(
                      //backgroundColor: Colors.transparent,
                      label: Text('Tag2'),
                      onPressed: () {
                        // update board with selection
                      }),
                  ActionChip(
                      label: Text('Tag3'),
                      onPressed: () {
                        // update board with selection
                      }),
                  ActionChip(
                      label: Text('Tag4'),
                      onPressed: () {
                        // update board with selection
                      }),
                ],
              )
            ],
          ),
        );
    
        Widget boardView = Container(
          color: Colors.blue,
          child: ListView.builder(
            scrollDirection: Axis.vertical,
            itemCount: 15,
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                onTap: () {},
                title: Row(
                  children: <Widget>[
                    Expanded(child: Text("This is item name")),
                    Text("12 Dec 18"),
                  ],
                ),
              );
            },
          ),
        );
    
        //  int _value=0;
        return Scaffold(
            appBar: AppBar(
              elevation: 1.0,
              title: Text("Test title"),
            ),
            body: Container(
              color: Colors.amber,
              child: new Column(
                children: <Widget>[
                  tagList,
                  Expanded(
                    child: boardView,
                  )
                ],
              ),
              margin: EdgeInsets.all(10.0),
            ));
      }
    }
    

    以下是思考过程: 我开始清理每个小部件并确保它们能够正确显示。在 taglist 小部件中,请注意您有一行作为列中的唯一小部件。在boardView中,LisView也是一列中唯一的元素;

    然后我添加了更多项目以确保两个卷轴都能正常工作。添加scrollDirection: Axis.horizontal int tagList 确保了这一点。

    最后,是时候将它们放在一起并显示这两个元素了。删除顶部的 Container,因为 Scaffold 就足够了。然后只需将 boardView 放在 Expanded 小部件中即可。

    这是一个有趣的练习。 =D

    【讨论】:

    • 如何为水平列表指定 wrap_content 大小。
    【解决方案2】:

    使用这个技巧:

    1. 将您的Row 包装在SingleChildScrollView 中。
    2. SingleChildScrollView 中使用scrollDirection: Axis.horizontal
    3. 将 SingleChildScrollView 包装在您的 ListView 中。

    【讨论】:

      【解决方案3】:

      将 CustomScrollView 与 SliverListview 一起使用,那么您可以通过垂直滚动水平滚动来实现任何类型的视图。

      CustomScrollView(
          slivers: <Widget>[
           SliverList(
        delegate: new SliverChildBuilderDelegate(
          (context, index) {
            return Container(
              child: Row(
                children: <Widget>[
                  buildTitle(),
                  Expanded(
                    child: _buildList(),
                  ),
                ],
              ),
            );
          },
          childCount: array.length,
        ),
      );,
          ],
        );
      

      【讨论】:

        【解决方案4】:

        100% 定制

         import 'package:flutter/material.dart';
            
            import 'dart:math';
            
            
            class NestedScrolls extends StatefulWidget {
            static const   listHeader = ['Pakistan', 'China','Iran','Turkey'];
              @override
              _NestedScrollsState createState() => _NestedScrollsState();
            }
            
            class _NestedScrollsState extends State<NestedScrolls> {
             
            
            var position=0;
              var topHeader;
             Widget? applyWidget() {
            
               switch(position){
                 case 0:
                   setState(() {
                     topHeader = NestedScrolls.listHeader[0];
                   });
                   // return widget if user click over pakistan in tab bar
                   return grid();
                 case 1:
                   setState(() {
                     topHeader = NestedScrolls.listHeader[1];
                   });
                   return   list();
                 case 2:
                   setState(() {
                     topHeader = NestedScrolls.listHeader[2];
                   });
                   return Container(color: Colors.blue,
                     child: Center(child: Text(topHeader),),);
                 case 3:
                   setState(() {
                     topHeader = NestedScrolls.listHeader[3];
                   });
                   return Container(color: Colors.orange,
                     child: Center(child: Text(topHeader),),);
            
            
               }
            
            
            
              }
            @override
              void initState() {
                // TODO: implement initState
                super.initState();
                //initial header name when activity start first time
                 topHeader = NestedScrolls.listHeader[0];
              }
              @override
              Widget build(BuildContext context) {
                topHeader = topHeader;
                return Scaffold(
                  // Persistent AppBar that never scrolls
                  appBar: AppBar(
                    title: Text('AppBar'),
                    elevation: 0.0,
                  ),
                  body:
                       Column(
                        children: <Widget>[
                          ///header
                          Container(
                            alignment: Alignment.center,
                            color: Colors.blueGrey,
                            height: 90,
                            child: Text(NestedScrolls.listHeader[position]),
                          ),
                          /// tabBar
                          Container(
                            height: 60,
                            width: MediaQuery.of(context).size.width,
                            child: ListView.builder(
                                scrollDirection: Axis.horizontal,
                                itemCount: NestedScrolls.listHeader.length,
                                itemBuilder: (con, index) {
                                  return GestureDetector(
                                    onTap: () => setState(() {
                                      position=index;
                                      topHeader = NestedScrolls.listHeader[index];
            
                                    }),
                                    child: Padding(
                                      padding: const EdgeInsets.symmetric(
                                          vertical: 2.0, horizontal: 10),
                                      child: Container(alignment: Alignment.center,
                                          width: 100,
                                          color: topHeader==NestedScrolls.listHeader[index]?Colors.black26:Colors.transparent,
                                          child: Text(NestedScrolls.listHeader[index])),
                                    ),
                                  );
                                }),
                          ),
            
                        ///Widget
                        Expanded(
                              child: GestureDetector(
            
                                  // onHorizontalDragStart: (left){
                                  //    print('left : ${left.localPosition.direction}');
                                  // // left.globalPosition.dx
                                  //
                                  // },
                                  onHorizontalDragEnd: (start){
                                    print('start : ${start.velocity.pixelsPerSecond.dx}');
                                    if((start.velocity.pixelsPerSecond.dx)<-700){
                                      if(position<NestedScrolls.listHeader.length-1 && position>=0)
                                        setState(() {
                                          position=position+1;
                                        });
            
            
                                    }else{}
            
                                  if((start.velocity.pixelsPerSecond.dx)>900){
                                    if(position<=NestedScrolls.listHeader.length-1 && position>0)
                                      setState(() {
                                        position=position-1;
                                      });
            
                                    }
                                    print(position);
                                  },
                                  child: applyWidget()),
                            ),
            
                        ],
                      ),
                );
              }
            
              list() {
                return SingleChildScrollView(scrollDirection: Axis.vertical,
                  child: Container(
            
            
            
                          child: Column(children: [
                            for(var color in Colors.primaries)
                            Container(color: color, height: 100.0)
            
                          ],),
            
            
            
            
            
            
                  ),
                );
              }
            
              grid() {
                return  GridView.count(
                    padding: EdgeInsets.zero,
                    crossAxisCount: 3,
                    children: Colors.primaries.map((color) {
                      return Container(color: color, height: 100.0);
                    }).toList(),
                  );
              }
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-03-22
          • 2021-02-28
          • 1970-01-01
          • 2014-01-09
          • 1970-01-01
          • 1970-01-01
          • 2021-05-08
          相关资源
          最近更新 更多