具有动态子元素的Flutter可滚动布局

3
我想创建一个通用的布局,它接受一个子小部件作为参数,并按以下方式布置内容:
顶部有一个AppBar,一个标题(大标题),下面是内容(可以是任何内容)。底部有一个带有几个按钮的列。如果内容太大而无法适应屏幕,则除了AppBar之外的所有小部件都可以滚动。如果内容适合屏幕,则标题和内容应该对齐在顶部,按钮在底部。
为了展示我的意思,我创建了一张图纸:

很容易创建可滚动内容功能。但如果内容不需要滚动,我会遇到排版内容使按钮底部对齐的困难。
重要的是说,我不知道内容小部件或按钮的高度。它们是动态的,可以改变它们的高度。此外,标题是可选的,可以有两种不同的大小。
我尝试了以下方法:
导入 'package:flutter/material.dart';
class BaseScreen extends StatelessWidget {
  final String? title;
  final bool bigHeader;
  final Widget child;
  final Widget bottomButtons;

  const BaseScreen({
    Key? key,
    required this.child,
    required this.bottomButtons,
    this.bigHeader = true,
    this.title,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final AppBar appBar = AppBar(
      title: Text("AppBar"),
    );
    double minChildHeight = MediaQuery.of(context).size.height -
        MediaQuery.of(context).viewInsets.bottom -
        MediaQuery.of(context).viewInsets.top -
        MediaQuery.of(context).viewPadding.bottom -
        MediaQuery.of(context).viewPadding.top -
        appBar.preferredSize.height;

    if (title != null) {
      minChildHeight -= 20;
      if (bigHeader) {
        minChildHeight -= bigHeaderStyle.fontSize!;
      } else {
        minChildHeight -= smallHeaderStyle.fontSize!;
      }
    }
    final Widget content = Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        if (title != null)
          Text(
            title!,
            style: bigHeader ? bigHeaderStyle : smallHeaderStyle,
            textAlign: TextAlign.center,
          ),
        if (title != null)
          const SizedBox(
            height: 20,
          ),
        ConstrainedBox(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              child,
              bottomButtons,
            ],
          ),
          constraints: BoxConstraints(
            minHeight: minChildHeight,
          ),
        ),
      ],
    );
    return Scaffold(
      appBar: appBar,
      body: SingleChildScrollView(
        child: content,
      ),
    );
  }

  TextStyle get bigHeaderStyle {
    return TextStyle(fontSize: 20);
  }

  TextStyle get smallHeaderStyle {
    return TextStyle(fontSize: 16);
  }
}

滚动效果完美,但按钮没有对齐到底部。相反,它们直接对齐在内容下方。有人知道我该如何修复吗?

1
请使用以下方法:https://dev59.com/FOk5XIcBkEYKwwoY49wn#62097942 - Pavel
2个回答

4

这里输入图像描述

你可以在这里检查DartPad

customscrollview 教程

Scaffold(
          // bottomNavigationBar: ,
          appBar: AppBar(
            title: Text(" App Bar title ${widgets.length}"),
          ),
          //============
          body: CustomScrollView(
            slivers: [
              SliverFillRemaining(
                hasScrollBody: false,
                child: Column(
                  // controller: _mycontroller,
                  children: [
                    title,
                    ...contents,
                    
                    // ---------------------This give Expansion and button get down --------
                    Expanded(
                      child: Container(),
                    ),
                    // ---------------------This give Expansion and button get down --------
                    Buttons
                  ],
                ),
              )
            ],
          ))

我们可以借助于CustomScrollView组件和Expanded组件来实现。这里的Expanded组件只是在 widget 之间扩展。 示例代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),
  );
}

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var widgets = [];

  var _mycontroller = ScrollController();

  @override
  Widget build(BuildContext context) {
    var title = Center(
        child: Text(
      "Scrollable title ${widgets.length}",
      style: TextStyle(fontSize: 30),
    ));
    var contents = [
      ...widgets,
    ];
    var Buttons = Row(
      children: [
        Expanded(
            child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Container(
            height: 100,
            child: ElevatedButton(
              onPressed: () {
                setState(() {
                  widgets.add(Container(
                    height: 100,
                    child: ListTile(
                      title: Text(widgets.length.toString()),
                      subtitle: Text("Contents BTN1"),
                    ),
                  ));
                });
                // _mycontroller.jumpTo(widgets.length * 100);
              },
              child: Text("BTN1"),
            ),
          ),
        )),
        Expanded(
            child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Container(
            height: 100,
            child: ElevatedButton(
              onPressed: () {
                setState(() {
                  if (widgets.length > 0) {
                    widgets.removeLast();
                  }
                });
                // _mycontroller.jumpTo(widgets.length * 100);
              },
              child: Text("BTN2"),
            ),
          ),
        ))
      ],
    );
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: SafeArea(
        child: Scaffold(
            // bottomNavigationBar: ,
            appBar: AppBar(
              title: Text(" App Bar title ${widgets.length}"),
            ),
            body: CustomScrollView(
              slivers: [
                SliverFillRemaining(
                  hasScrollBody: false,
                  child: Column(
                    // controller: _mycontroller,
                    children: [
                      title,
                      ...contents,
                      Expanded(
                        child: Container(),
                      ),
                      Buttons
                    ],
                  ),
                )
              ],
            )),
      ),
    );
  }
}

问题在于我无法设置内容小部件的高度,因为它需要是灵活的。当我不明确设置高度时,就会出现这个错误:LayoutBuilder不支持返回固有尺寸 - Apri
可以提供一下代码吗? - lava
没事了,那是我的错误。我在布局上遇到了一些问题。不设置特定的高度也可以工作。 - Apri
刚刚注意到AutoSizeText不起作用。 - Apri

1

试试这个:

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BaseScreen(
        bottomButtons: [
          ElevatedButton(onPressed: () {}, child: const Text('Button 1')),
          ElevatedButton(onPressed: () {}, child: const Text('Button 2')),
        ],
        content: Container(
          color: Colors.lightGreen,
          height: 200,
        ),
        title: 'Title',
      ),
    );
  }
}

class BaseScreen extends StatelessWidget {
  final bool bigHeader;
  final List<Widget> bottomButtons;
  final String? title;
  final Widget content;

  const BaseScreen({
    this.bigHeader = true,
    required this.bottomButtons,
    required this.content,
    this.title,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AppBar'),
      ),
      body: CustomScrollView(
        slivers: [
          SliverFillRemaining(
            hasScrollBody: false,
            child: Column(
              children: [
                if (title != null)
                  Padding(
                    padding: const EdgeInsets.symmetric(vertical: 12),
                    child: Text(
                      title!,
                      style: bigHeader ? _bigHeaderStyle : _smallHeaderStyle,
                      textAlign: TextAlign.center,
                    ),
                  ),
                content,
                const Spacer(),
                ...bottomButtons,
              ],
            ),
          ),
        ],
      ),
    );
  }

  TextStyle get _bigHeaderStyle => const TextStyle(fontSize: 20);
  
  TextStyle get _smallHeaderStyle => const TextStyle(fontSize: 16);
}

截图:

未滚动

向上滚动

向下滚动


问题在于我无法设置内容小部件的高度,因为它需要是灵活的。当我不明确设置高度时,就会出现这个错误:LayoutBuilder不支持返回固有尺寸 - Apri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接