【问题标题】:Animate scrollable widgets to fill one another's space on scroll in another widget动画可滚动小部件以在另一个小部件滚动时填充彼此的空间
【发布时间】:2022-12-11 20:05:25
【问题描述】:

这是一个包含三个主要小部件的应用程序:大小框和两个可滚动的ListViews,一个在SizedBox() 内,另一个在Expanded() 内。

我要做的是让BottomList在滚动时向上移动并占据TopList的位置,如果TopList滚动则移动到BottomList的原始位置。我如何实现这一目标?

MRE:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('two scrolls')),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Widget1: this box should stay in place
          SizedBox(
            height: MediaQuery.of(context).size.height / 5,
            child: Container(
              color: Colors.purple,
            ),
          ),
          // TopList: this box should shrink to the top until it hits some minimum height, on scroll in BottomList
          // If it is scrolled after Widget3 took all the space, expand its contents to bottom to a set height.
          SizedBox(
            // has half of remaining height
            height: MediaQuery.of(context).size.height / 2 - MediaQuery.of(context).size.height / 5 - kToolbarHeight,
            child: ListView(
              children: [
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.red,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.blue,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.red,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.blue,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.red,
                ),
              ],
            ),
          ),
          const Divider(height: 16, thickness: 0.5, color: Colors.black),
          // BottomList: on scroll, should expand upwards to fill the space of TopList until it hits TopList_minHeight, then scroll as usual.
          // On scroll of TopList, should move to it's original position.
          Expanded(
            child: ListView(
              children: [
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.red,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.blue,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.red,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.blue,
                ),
                Container(
                  width: 160.0,
                  height: 160.0,
                  color: Colors.red,
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

【问题讨论】:

    标签: flutter


    【解决方案1】:

    您可以将侦听器添加到调整顶部列表小部件高度的ScrollController。 请注意,在这种情况下,您需要手动处理 ScrollController。

    import 'package:flutter/material.dart';
    import 'dart:math';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      late final ScrollController topScrollController;
      late final ScrollController bottomScrollController;
      double topOffset = 0;
      @override
      void initState() {
        super.initState();
        topScrollController = ScrollController();
        topScrollController.addListener(() {
          setState(() {
            topOffset = 0;
          });
        });
    
        bottomScrollController = ScrollController();
        bottomScrollController.addListener(() {
          setState(() {
            topOffset = bottomScrollController.offset;
          });
        });
      }
    
      @override
      void dispose() {
        topScrollController.dispose();
        bottomScrollController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        final topMaxHeight = MediaQuery.of(context).size.height / 2 -
            MediaQuery.of(context).size.height / 5 -
            kToolbarHeight;
        const topMinHeight = 50.0;
        double height = topOffset <= 200
            ? topMaxHeight
            : max(topMaxHeight + 200 - topOffset, topMinHeight);
    
        return Scaffold(
          // appBar: AppBar(title: const Text('two scrolls')),
          body: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // Widget1: this box should stay in place
              SizedBox(
                height: MediaQuery.of(context).size.height / 5,
                child: Container(
                  color: Colors.purple,
                ),
              ),
              // TopList: this box should shrink to the top until it hits some minimum height, on scroll in BottomList
              // If it is scrolled after Widget3 took all the space, expand its contents to bottom to a set height.
    
              SizedBox(
                // has half of remaining height
                height: height,
                child: ListView(
                  controller: topScrollController,
                  children: [
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.green,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.purple,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.green,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.purple,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.green,
                    ),
                  ],
                ),
              ),
              const Divider(height: 16, thickness: 0.5, color: Colors.black),
              // BottomList: on scroll, should expand upwards to fill the space of TopList until it hits TopList_minHeight, then scroll as usual.
              // On scroll of TopList, should move to it's original position.
              Expanded(
                child: ListView(
                  controller: bottomScrollController,
                  children: [
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.red,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.blue,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.red,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.blue,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.red,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.blue,
                    ),
                    Container(
                      width: 160.0,
                      height: 160.0,
                      color: Colors.red,
                    ),
                  ],
                ),
              )
            ],
          ),
        );
      }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-10
      • 2019-05-23
      • 1970-01-01
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多