在Flutter中滚动CustomMultiChildLayout

问题描述

我认为这是一个非常简单的布局,它为Flutter初学者带来了一些特别棘手的问题。但是,我正在取得良好的进展,并在此过程中学习了一些经验教训。我已经能够进行自定义布局,其中的小部件绝对定位,因此其中一个小部件在折叠下方对齐。

小部件集合是无状态AuthLayout小部件。下图显示AuthLayout在首次显示时如何对齐其子级。用户应该能够向上滚动页面显示“折痕以下”的蓝色部分。

enter image description here

就像其他有关此布局的内容一样,我认为这很简单,但到目前为止还没有运气。我已经尝试过CustomScrollViewSingleChildScrollView,但是没有将AuthLayout放在具有硬编码高度的容器中,所以我一直没有办法解决问题。

以下是硬编码容器高度的代码,以允许折叠后的蓝色框滚动到视口中。我想要这种行为,但是要支持一个蓝色的框,其高度在构建时未知。

import 'package:Flutter/material.dart';

class AuthPage extends StatelessWidget {
  const AuthPage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      child: LayoutBuilder(builder: (ctx,constraints) {
        return Stack(
          children: [
            Align(
              alignment: Alignment.topCenter,child: logo(),),SingleChildScrollView(
              physics: ClampingScrollPhysics(),child: Container(
                height: constraints.maxHeight + 300,// here is the hardcoded height
                child: AuthLayout(screenHeight: constraints.maxHeight),],);
      }),);
  }
}

enum AuthWidgets { form,action,disclaimer }

class AuthLayoutDelegate extends MultiChildLayoutDelegate {
  AuthLayoutDelegate({@required screenHeight}) : _screenHeight = screenHeight;

  double _overlap = 50;
  double _screenHeight;

  @override
  void performlayout(Size size) {
    var formSize = layoutChild(AuthWidgets.form,BoxConstraints.loose(size));
    var actionSize = layoutChild(AuthWidgets.action,BoxConstraints.loose(size));
    var disclaimerSize =
        layoutChild(AuthWidgets.disclaimer,BoxConstraints.loose(size));

    if (formSize != null && actionSize != null && disclaimerSize != null) {
      // Need the height of the form and action area,minus the overlap
      var aboveTheFold = formSize.height + actionSize.height - _overlap;

      var offsetY = _screenHeight - aboveTheFold;

      offsetY += formSize.height - _overlap;
      positionChild(AuthWidgets.action,Offset(0,offsetY));

      offsetY += actionSize.height;
      positionChild(AuthWidgets.disclaimer,offsetY));

      positionChild(AuthWidgets.form,_screenHeight - aboveTheFold));
    }
  }

  @override
  bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
    return false;
  }
}

class AuthLayout extends StatelessWidget {
  const AuthLayout({@required this.screenHeight,Key key}) : super(key: key);

  final double screenHeight;

  @override
  Widget build(BuildContext context) {
    return CustomMultiChildLayout(
      delegate: AuthLayoutDelegate(screenHeight: screenHeight),children: [
        LayoutId(id: AuthWidgets.action,child: ActionMenu()),LayoutId(id: AuthWidgets.disclaimer,child: disclaimer()),LayoutId(id: AuthWidgets.form,child: SignInForm()),);
  }
}

class logo extends StatelessWidget {
  const logo({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 64,color: Colors.blue,child: Center(child: Text('logo')),);
  }
}

class SignInForm extends StatelessWidget {
  const SignInForm({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 16),child: Container(
        color: Colors.red.withOpacity(0.5),height: 350,child: Center(
          child: Text('SignInForm'),);
  }
}

class disclaimer extends StatelessWidget {
  const disclaimer({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,color: Colors.blue.withOpacity(0.5),child: Center(child: Text('disclaimer')),);
  }
}

class ActionMenu extends StatelessWidget {
  const ActionMenu({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 200,color: Colors.green.withOpacity(0.5),child: Center(child: Text('ActionMenu')),);
  }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)