Flutter这种布局应该怎么弄

image.png
有时候内容可能比较少,中间就会出现空白区域,但要求按钮要在最底部。但如果内容比较多,空白区域就会减少,如果屏幕都不够显示内容,那么就继续往下挤,使出现可滚动效果,这个时候是希望按钮也可以随着滚动,而不是始终保持在屏幕的底部。

阅读 2.1k
2 个回答
CustomScrollView(
        slivers: [
            SliverToBoxAdapter(
                child: Column(
                    children: const [
                        FlutterLogo(size: 100),
                        FlutterLogo(size: 100),
                        FlutterLogo(size: 100),
                    ],
                ),
            ),
            SliverFillRemaining(
                hasScrollBody: false,
                child: Container(
                    alignment: Alignment.bottomCenter,
                    padding: const EdgeInsets.only(bottom: 10),
                    child: ElevatedButton(onPressed: (){}, child: const Text("Button")),
                ),
            )
        ],
    )

试了一下,你参考参考:

import 'dart:async';
import 'package:flutter/material.dart';

class TestScreenPage extends StatefulWidget {
  const TestScreenPage({Key? key}) : super(key: key);

  @override
  State<TestScreenPage> createState() => _TestScreenPageState();
}

class _TestScreenPageState extends State<TestScreenPage> {
  List<String> lists = ['test 0'];
  ScrollController scrollController = ScrollController();
  GlobalKey centerKey = GlobalKey();
  double? height;

  @override
  void initState() {
    super.initState();
    initItems();
  }

  void initItems() {
    Timer.periodic(const Duration(milliseconds: 1000), (timer) {
      lists.add('test ${lists.length}');
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Builder(builder: (ct) {
          height ??= MediaQuery.of(ct).size.height;
          final padding = MediaQuery.of(context).padding.vertical;
          const buttonHeight = 52.0;
          final centerPadding =
              height! - 56 * lists.length - padding - buttonHeight;
          print(
              "height: $height, padding: $padding, centerPadding: $centerPadding");
          return Container(
            color: Colors.red,
            child: CustomScrollView(
              controller: scrollController,
              slivers: [
                SliverList(
                  delegate: SliverChildBuilderDelegate(
                    (ct, index) => Container(
                      color: Colors.green,
                      height: 56,
                      child: Text(lists[index]),
                    ),
                    childCount: lists.length,
                  ),
                ),
                SliverPadding(
                  key: centerKey,
                  padding: EdgeInsets.only(
                      top: centerPadding < 0 ? 0 : centerPadding),
                ),
                SliverList(
                  delegate: SliverChildBuilderDelegate(
                    (ct, index) => TextButton(
                        style: ButtonStyle(
                          padding: MaterialStateProperty.all(
                              const EdgeInsets.all(0)),
                          fixedSize: MaterialStateProperty.all(
                              const Size(double.infinity, buttonHeight)),
                        ),
                        onPressed: () {},
                        child: const Text("button")),
                    childCount: 1,
                  ),
                ),
              ],
            ),
          );
        }),
      ),
    );
  }
}

改成这样实现呢?

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';

class TestScreenPage extends StatefulWidget {
  const TestScreenPage({Key? key}) : super(key: key);

  @override
  State<TestScreenPage> createState() => _TestScreenPageState();
}

class _TestScreenPageState extends State<TestScreenPage> {
  List<Map<String, dynamic>> lists = [
    {'name': 'test 0', 'height': 56.0}
  ];
  ScrollController scrollController = ScrollController();
  GlobalKey centerKey = GlobalKey();
  double? height;
  bool canScroll = false;
  bool firstBuild = false;

  @override
  void initState() {
    super.initState();
    initItems();
  }

  void initItems() {
    scrollController.addListener(() {
      print(scrollController.position);
      if (!canScroll) {
        setState(() => canScroll = true);
        _jumpToMaxExtent();
      }
    });
    Timer.periodic(const Duration(milliseconds: 1000), (timer) {
      final height = Random().nextDouble() * 56;
      setState(
          () => lists.add({'name': 'test ${lists.length}', 'height': height}));
      _jumpToMaxExtent();
    });
  }

  Future _jumpToMaxExtent() async {
    await Future.delayed(const Duration(milliseconds: 20));
    scrollController.animateTo(
      scrollController.position.maxScrollExtent,
      duration: const Duration(milliseconds: 200),
      curve: Curves.ease,
    );
  }

  void afterBuild() {
    firstBuild = true;
    Future.delayed(const Duration(milliseconds: 200), () async {
      final maxExtent = scrollController.position.maxScrollExtent;
      if (maxExtent >= MediaQuery.of(context).size.height) {
        setState(() => canScroll = true);
        await Future.delayed(const Duration(milliseconds: 20));
        scrollController.animateTo(
          maxExtent,
          duration: const Duration(milliseconds: 200),
          curve: Curves.ease,
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Builder(
          builder: (ct) {
            Widget widget = Column(
              children: [
                Expanded(
                  child: ListView(
                    controller: scrollController,
                    physics: const ClampingScrollPhysics(),
                    children: List.generate(
                      lists.length,
                      (index) => Container(
                        color: Colors.red,
                        height: lists[index]['height'],
                        child: Text(lists[index]['name']),
                      ),
                    ),
                  ),
                ),
                TextButton(
                    style: ButtonStyle(
                      padding:
                          MaterialStateProperty.all(const EdgeInsets.all(0)),
                    ),
                    onPressed: () {},
                    child: const Text("button")),
              ],
            );
            if (!firstBuild) afterBuild();
            if (canScroll) {
              widget = ListView(
                controller: scrollController,
                physics: const ClampingScrollPhysics(),
                children: [
                  ...List.generate(
                    lists.length,
                    (index) => Container(
                      color: Colors.black26,
                      height: lists[index]['height'],
                      child: Text(lists[index]['name']),
                    ),
                  ),
                  TextButton(
                      style: ButtonStyle(
                        padding:
                            MaterialStateProperty.all(const EdgeInsets.all(0)),
                      ),
                      onPressed: () {},
                      child: const Text("button")),
                ],
              );
            }
            return widget;
          },
        ),
      ),
    );
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题