How to use Expanded in SingleChildScrollView?

前端 未结 7 1695
北荒
北荒 2020-11-29 21:24

How to use Expanded in SingleChildScrollView? I have a screen with Image.network, ListView.builder and Row (

相关标签:
7条回答
  • 2020-11-29 21:31

    Try this,

    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"),
                ],
              ),
            ),
          ),
        );
      },
    )
    

    I got this solution from git issues when I get into the same situation. I don't have the git link. I think it may help you.

    Reusable widget:

    Note: use it, only if one of the children is 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,
                    ),
                  ),
                ),
              ),
            );
          },
        );
      }
    }
    
    0 讨论(0)
  • 2020-11-29 21:45

    Instead of using SingleChildScrollView, It's easier to use CustomScrollView with a SliverFillRemaining.

    Try this:

    CustomScrollView(
      slivers: [
        SliverFillRemaining(
          hasScrollBody: false,
          child: Column(
            children: <Widget>[
              const Text('Header'),
              Expanded(child: Container(color: Colors.red)),
              const Text('Footer'),
            ],
          ),
        ),
      ],
    )
    
    0 讨论(0)
  • 2020-11-29 21:48

    As already pointed out, because you are using a scrollable, you can't expand to the infinity (theoretically speaking), that's what's happening when you try to expand your ListView that is nested in a SingleChildScrollView.

    You can try using a NestedScrollView, or, if it fits your demands and because you have commented out this line:

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

    You can just wrap your ListView in a ConstrainedBox (or even just a regular Container) with that height, for example, instead of the Expanded, like so:

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

    Since you are already in a scrollable, you shouldn't have issues with smaller screens, because the whole tree is scrollable.

    0 讨论(0)
  • 2020-11-29 21:49

    The answer is in the error itself. When the column is inside a view that is scrollable, the column is trying to shrink-wrap its content but since you used Expanded as a child of the column it is working opposite to the column trying to shrink-wrap its children. This is causing this error because these two directives are completely opposite to each other.

    As mentioned in the error logs try the following:

    Consider setting mainAxisSize to MainAxisSize.min (for column) and using FlexFit.loose fits for the flexible(use Flexible rather than Expanded).

    0 讨论(0)
  • 2020-11-29 21:52

    Simply wrap your SingleChildScrollView in a Center or an Align element.

    Example :

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

    or

      Center(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              ...
            ]
          }
        }
      }
    
    0 讨论(0)
  • 2020-11-29 21:55

    The trick is to only apply the ScrollView when you need to, and otherwise to let the content expand.

    Something like this works well:

    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,
              ),
            );
          },
        );
      }
    }
    

    Usage:

    ConstrainedFlexView(600, child: FlexContent())
    

    This will flex to fill all vertical space, but once the widget is <600px it will switch to a constrained box + scroll view, allowing the content not to be squished too much.

    0 讨论(0)
提交回复
热议问题