求助一个关于ListView和expandablelistview的刷新问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求助一个关于ListView和expandablelistview的刷新问题相关的知识,希望对你有一定的参考价值。

参考技术A 直接说解决办法吧:

  其实还是需要计算出adapter的所有item的高度,再设置给listiew。

上代码,是一个封装好的方法,在listview.setAdapter()之后调用此方法就行了

如何在 SingleChildScrollView 中使用 Expanded?

【中文标题】如何在 SingleChildScrollView 中使用 Expanded?【英文标题】:How to use Expanded in SingleChildScrollView? 【发布时间】:2019-10-13 00:37:13 【问题描述】:

如何在SingleChildScrollView中使用Expanded?我有一个带有Image.networkListView.builderRowTextFormFieldIconButton)的屏幕。我用Expanded 包裹了ListView。如何用SingleChildScrollView 包装此列?我需要在键盘打开时移动屏幕才能看到我在写什么。当我包装我的专栏时,我遇到了这个错误。

      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Container(
              child: GestureDetector(
                child:
                Image.network(
                  postOne.imageUrl,
                  fit: BoxFit.fitWidth,
                  height: MediaQuery
                      .of(context)
                      .size
                      .width,
                  width: MediaQuery
                      .of(context)
                      .size
                      .width,
                ),
                onLongPress: () ,
                onDoubleTap: () ,
              ),
            ),
            Expanded(
              //height: MediaQuery.of(context).size.width*0.33,
              child: ListView.builder(
                  itemCount: commentList.length,
                  itemBuilder: (context, position) 
                    return GestureDetector(
                        onLongPress: () ,
                        child: Card(
                          child: Padding(
                            padding: EdgeInsets.all(5.0),
                            child: new CheckboxListTile(
                                title: new Text(commentList
                                    .elementAt(position)
                                    .coment,
                                  style: TextStyle(fontSize: 18.0),),
                                value: values[commentList
                                    .elementAt(position)
                                    .coment],
                                onChanged: (bool value) ),
                          ),
                        )
                    );
                  
              ),
            ),
            Container(
              child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    new Flexible(
                      child: Theme(
                        data: new ThemeData(
                            brightness: Brightness.light,
                            primarySwatch: Colors.grey,
                            inputDecorationTheme: new InputDecorationTheme(
                              labelStyle: new TextStyle(
                                  color: Colors.black45, fontSize: 18.0
                              ),
                            )
                        ),
                        child: new Form(
                          key: _formKey,
                          child: new TextFormField(
                            validator: (value) 
                              if (value.isEmpty) 
                                return 'Please enter the comment';
                              
                            ,
                            controller: commentController,
                            decoration: new InputDecoration(
                              labelText: "Add comment",
                              //hintText: 'Add comment'
                            ),
                            keyboardType: TextInputType.text,
                          ),
                        ),
                      ),
                    ),
                    new Container(
                        margin: EdgeInsets.only(left: 10.0, top: 12.0),
                        child: new IconButton(
                            icon: new Icon(Icons.send, color: Colors.black,),
                            onPressed: () 
                        )
                    ),
                  ]),
            ),
          ],
        ),
      ),
I/flutter ( 6816): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter ( 6816): The following assertion was thrown during performLayout():
I/flutter ( 6816): RenderFlex children have non-zero flex but incoming height constraints are unbounded.
I/flutter ( 6816): When a column is in a parent that does not provide a finite height constraint, for example if it is
I/flutter ( 6816): in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a
I/flutter ( 6816): flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining
I/flutter ( 6816): space in the vertical direction.
I/flutter ( 6816): These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child
I/flutter ( 6816): cannot simultaneously expand to fit its parent.
I/flutter ( 6816): Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible
I/flutter ( 6816): children (using Flexible rather than Expanded). This will allow the flexible children to size
I/flutter ( 6816): themselves to less than the infinite remaining space they would otherwise be forced to take, and
I/flutter ( 6816): then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum
I/flutter ( 6816): constraints provided by the parent.
I/flutter ( 6816): The affected RenderFlex is:
I/flutter ( 6816):   RenderFlex#9f534 relayoutBoundary=up11 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 6816): The creator information is set to:
I/flutter ( 6816):   Column ← _SingleChildViewport ← IgnorePointer-[GlobalKey#3670d] ← Semantics ← Listener ←
I/flutter ( 6816):   _GestureSemantics ← RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#4878e] ←
I/flutter ( 6816):   Listener ← _ScrollableScope ← _ScrollSemantics-[GlobalKey#c5885] ← RepaintBoundary ← CustomPaint ←
I/flutter ( 6816):   ⋯
I/flutter ( 6816): The nearest ancestor providing an unbounded width constraint is:
I/flutter ( 6816):   _RenderSingleChildViewport#155d8 relayoutBoundary=up10 NEEDS-LAYOUT NEEDS-PAINT
I/flutter ( 6816):   creator: _SingleChildViewport ← IgnorePointer-[GlobalKey#3670d] ← Semantics ← Listener ←
I/flutter ( 6816):   _GestureSemantics ← RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#4878e] ←
I/flutter ( 6816):   Listener ← _ScrollableScope ← _ScrollSemantics-[GlobalKey#c5885] ← RepaintBoundary ← CustomPaint ←
I/flutter ( 6816):   RepaintBoundary ← ⋯
I/flutter ( 6816):   parentData: <none> (can use size)
I/flutter ( 6816):   constraints: BoxConstraints(0.0<=w<=440.8, 0.0<=h<=649.3)
I/flutter ( 6816):   size: MISSING
I/flutter ( 6816): See also: https://flutter.dev/layout/
I/flutter ( 6816): If this message did not help you determine the problem, consider using debugDumpRenderTree():
I/flutter ( 6816):   https://flutter.dev/debugging/#rendering-layer
I/flutter ( 6816):   http://docs.flutter.io/flutter/rendering/debugDumpRenderTree.html
I/flutter ( 6816): If none of the above helps enough to fix this problem, please don't hesitate to file a bug:
I/flutter ( 6816):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 6816): 

【问题讨论】:

你不能结合 singlechildscoolview -> 列 -> 扩展的 whitout 给出一个高度。将你的 singlechildscoolview 包装在一个容器或 sizebox 中,高度为:MediaQuery.of(context).size.height. 如果我理解正确this 就是你要找的... 【参考方案1】:

使用CustomScrollViewSliverFillRemaining 相比,使用CustomScrollView 更容易。

试试这个:

CustomScrollView(
  slivers: [
    SliverFillRemaining(
      hasScrollBody: false,
      child: Column(
        children: <Widget>[
          const Text('Header'),
          Expanded(child: Container(color: Colors.red)),
          const Text('Footer'),
        ],
      ),
    ),
  ],
)

【讨论】:

荣誉。比 Crazy Lazy Cat 的解决方案效果更好;并避免 IntrinsicHeight 不确定效果是否符合预期,但如果您在页面上打开键盘,展开的小部件会缩小。 CustomScrollView 不考虑键盘溢出 这是最好的解决方案,因为它不会错过您的列布局和IntrinsicHeight【参考方案2】:

试试这个,

LayoutBuilder(
  builder: (context, constraint) 
    return SingleChildScrollView(
      child: ConstrainedBox(
        constraints: BoxConstraints(minHeight: constraint.maxHeight),
        child: IntrinsicHeight(
          child: Column(
            children: <Widget>[
              Text("Header"),
              Expanded(
                child: Container(
                  color: Colors.red,
                ),
              ),
              Text("Footer"),
            ],
          ),
        ),
      ),
    );
  ,
)

当我遇到同样的情况时,我从 git 问题中得到了这个解决方案。我没有 git 链接。我想它可能会对你有所帮助。

可重复使用的小部件:

注意:仅当其中一个孩子是Expanded时才使用它

import 'package:flutter/material.dart';

class ScrollColumnExpandable extends StatelessWidget 
  final List<Widget> children;
  final CrossAxisAlignment crossAxisAlignment;
  final MainAxisAlignment mainAxisAlignment;
  final VerticalDirection verticalDirection;
  final TextDirection textDirection;
  final TextBaseline textBaseline;
  final EdgeInsetsGeometry padding;

  const ScrollColumnExpandable(
    Key key,
    this.children,
    CrossAxisAlignment crossAxisAlignment,
    MainAxisAlignment mainAxisAlignment,
    VerticalDirection verticalDirection,
    EdgeInsetsGeometry padding,
    this.textDirection,
    this.textBaseline,
  )  : crossAxisAlignment = crossAxisAlignment ?? CrossAxisAlignment.center,
        mainAxisAlignment = mainAxisAlignment ?? MainAxisAlignment.start,
        verticalDirection = verticalDirection ?? VerticalDirection.down,
        padding = padding ?? EdgeInsets.zero,
        super(key: key);

  @override
  Widget build(BuildContext context) 
    final children = <Widget>[const SizedBox(width: double.infinity)];

    if (this.children != null) children.addAll(this.children);
    return LayoutBuilder(
      builder: (context, constraint) 
        return SingleChildScrollView(
          child: Padding(
            padding: padding,
            child: ConstrainedBox(
              constraints: BoxConstraints(
                minHeight: constraint.maxHeight - padding.vertical,
              ),
              child: IntrinsicHeight(
                child: Column(
                  crossAxisAlignment: crossAxisAlignment,
                  mainAxisAlignment: mainAxisAlignment,
                  mainAxisSize: MainAxisSize.max,
                  verticalDirection: verticalDirection,
                  children: children,
                  textBaseline: textBaseline,
                  textDirection: textDirection,
                ),
              ),
            ),
          ),
        );
      ,
    );
  

【讨论】:

constraint.maxHeight 在我的代码中无法识别!! @evals 你忘了复制 LayoutBuilder( builder: (context, constraint) 这真是救命稻草,非常感谢! IntrinsicHeight 对我来说是缺失的部分。 我相信这是您所指的 git 问题:github.com/flutter/flutter/issues/18711 BoxConstraints 强制无限高。有问题的约束是:BoxConstraints(0.0 【参考方案3】:

答案就在错误本身。当该列位于可滚动视图内时,该列正在尝试收缩包装其内容,但由于您使用 Expanded 作为该列的子级,它的工作方式与尝试收缩包装其子级的列相反。这是导致此错误的原因,因为这两个指令彼此完全相反。

如错误日志中所述,请尝试以下操作:

考虑将mainAxisSize 设置为MainAxisSize.min(用于列)并使用FlexFit.loose 适合灵活(使用Flexible 而不是Expanded)。

【讨论】:

你能补充一些话来解释为什么这两个参数有效吗? 我只是想出了一个摆脱 Expanded 的方法。然后 minAxisSize 为我工作。【参考方案4】:

我尝试了 Vijaya Ragavan 解决方案,但对其进行了一些调整,它仍然有效。 要将ExpandedSingleChildScrollView 一起使用,我使用了ConstrainedBox 并将其高度设置为屏幕高度(使用MediaQuery)。您只需要确保您放入ConstrainedBox 的屏幕内容不大于屏幕的高度。

否则将ConstrainedBox 的高度设置为您要在屏幕上显示的内容的高度。

SingleChildScrollView(
    child: ConstrainedBox(
        constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height),
        child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
                Expanded(
                    child: Text('Hello World!'),
                ),
            ],
        ),
    )
)

编辑: 要减去AppBar 和/或状态栏的高度,请参见下文:

double screenHeightMinusAppBarMinusStatusBar = MediaQuery.of(context).size.height 
    - appBar.preferredSize.height
    - MediaQuery.of(context).padding.top;

【讨论】:

LayoutBuilder 实际上会为您提供 SingleChildScrollView 可以拥有的剩余空间。 MediaQuery.of(context).size.height 将为您提供设备屏幕的总高度(AppBar 已经占用了一些空间) LayoutBuilder 听起来确实更好。但是如果有人想使用 MediaQuery,您将需要减去 AppBar 高度(如果 SingleChildScrollView 是具有 appBar 的 Scaffold 的小部件子级)和/或减去状态/通知栏高度(如果 SingleChildScrollView 是SafeArea) 从屏幕总高度,例如:double screenHeightMinusAppBarMinusStatusBar = MediaQuery.of(context).size.height - appBar.preferredSize.height - MediaQuery.of(context).padding.top 好吧,我收到一个语法错误,它告诉我“未定义名称 appBar” 所以基本上他使用 Expanded 来动态地适应整个高度,而你设置一个固定的高度。你真是个天才【参考方案5】:

只需将您的SingleChildScrollView 包装在CenterAlign 元素中。

例子:

  Align(
    alignment: Alignment.topCenter,
    child: SingleChildScrollView(
      child: Column(
        children: <Widget>[
          ...
        ]
      
    
  

  Center(
    child: SingleChildScrollView(
      child: Column(
        children: <Widget>[
          ...
        ]
      
    
  

【讨论】:

使用 Center 实际上对我有用。 Scaffold(Center(Scrollbar(SingleChildScrollView(Container(...)))))【参考方案6】:

诀窍是只在需要时应用 ScrollView,否则让内容展开。

这样的东西效果很好:

class ConstrainedFlexView extends StatelessWidget 
  final Widget child;
  final double minSize;
  final Axis axis;

  const ConstrainedFlexView(this.minSize, Key key, this.child, this.axis) : super(key: key);

  bool get isHz => axis == Axis.horizontal;

  @override
  Widget build(BuildContext context) 
    return LayoutBuilder(
      builder: (_, constraints) 
        double viewSize = isHz ? constraints.maxWidth : constraints.maxHeight;
        if (viewSize > minSize) return child;
        return SingleChildScrollView(
          scrollDirection: axis ?? Axis.vertical,
          child: ConstrainedBox(
            constraints: BoxConstraints(
                maxHeight: isHz ? double.infinity : minSize, 
                maxWidth: isHz ? minSize : double.infinity),
            child: child,
          ),
        );
      ,
    );
  

用法:

ConstrainedFlexView(600, child: FlexContent())

这将弯曲以填充所有垂直空间,但是一旦小部件

【讨论】:

【参考方案7】:

正如已经指出的那样,因为您使用的是可滚动的,所以您无法扩展到无穷大(理论上来说),当您尝试扩展嵌套的 ListView 时会发生这种情况在SingleChildScrollView

您可以尝试使用NestedScrollView,或者,如果它符合您的要求并且因为您已注释掉这一行:

//height: MediaQuery.of(context).size.width*0.33,

例如,您可以将ListView 包裹在具有该高度的ConstrainedBox(甚至只是普通的Container)中,而不是Expanded,如下所示:

 Container(
         height: MediaQuery.of(context).size.width*0.33,
              child: ListView.builder(
                  itemCount: commentList.length,
                ...
               )
          )

由于您已经处于可滚动状态,因此较小的屏幕应该不会有问题,因为整个树都是可滚动的。

【讨论】:

【参考方案8】:

如果你想要的是:

能够在 SingleChildScrollView 内使用扩展来填充剩余的屏幕。 不被键盘打扰,要么隐藏您正在写入的 TextFormField,要么调整 SingleChildScrollView 的内容大小。

我遇到了同样的问题。 这可能是危险的,但在我的情况下,我使用了可行的解决方案:

import 'package:flutter/material.dart';

class FiniteSizeSingleChildScrollViewNotBotheredByKeyboard
    extends StatefulWidget 
  final Widget child;

  const FiniteSizeSingleChildScrollViewNotBotheredByKeyboard(
      Key? key, required this.child)
      : super(key: key);

  @override
  State<FiniteSizeSingleChildScrollViewNotBotheredByKeyboard> createState() =>
      _FiniteSizeSingleChildScrollViewNotBotheredByKeyboardState();


class _FiniteSizeSingleChildScrollViewNotBotheredByKeyboardState
    extends State<FiniteSizeSingleChildScrollViewNotBotheredByKeyboard> 
  double width = 0, height = 0;

  @override
  Widget build(BuildContext context) 
    return LayoutBuilder(builder: (context, constraints) 
      if (width != constraints.maxWidth) 
        width = constraints.maxWidth;
        height = constraints.maxHeight;
      
      return SingleChildScrollView(
        child: SizedBox(
          width: width,
          height: height,
          child: widget.child,
        ),
      );
    );
  



这个想法是在 SingleChildScrollView 之前获取可用大小,然后将该大小注入到 SingleChildScrollView 内部的 SizedBox 中。另外,为了避免键盘改变这个大小,如果宽度没有改变,有一个 if 条件可以防止改变高度。

我对这个自定义小部件唯一没有考虑的问题是,如果这个小部件内部的 TextFormField 控制器(我们称之为小部件 A)在包含该小部件 A 的小部件 B 上调用 setState,该小部件 A 本身是关联的键控表单的子项使用 TextFormField,控制器将触发重建,同时键盘将触发小部件 A 的重建,这会产生异常。为了避免这种情况,请将键控表单放在小部件 A 内(而不是上面)。

【讨论】:

以上是关于求助一个关于ListView和expandablelistview的刷新问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在QML中设计一个expandable ListView

Flutter - 使用 Column/Expanded/ListView 的布局问题

scrollview下Expandable Listview的setOnScrollListener()

Android - 如何在 Android 的 Expandable ListView 的子视图下添加另一个视图?

求助scrollview嵌套viewpager 放listview 不能滑动

求助,如何在listview里addheadview-Android开发问答