我想在颤栗中建造这样的东西。
flutter - 我们怎么能在 flutter 中实现这样的东西呢?-LMLPHP
我尝试过使用slivers,但在动画到达顶部时无法获得所需的输出。
主要的理想功能如下。
1.行为类似于列表视图,但卡片应堆叠在屏幕顶部。
2.抽头列表应选择并显示为主卡,如所附图片所示。

import 'dart:math' as math;

class FlashCards extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: Text("Flash Cards"),
            backgroundColor: Colors.black,
          ),
          body: StackedList()),
    );
  }
}

class StackedList extends StatefulWidget {
  @override
  _StackedListState createState() => _StackedListState();
}

class _StackedListState extends State<StackedList> {
  static const _minHeight = 16.0;
  //var _maxHeight = 120.0;
  bool _tapped = false;
  final List<Color> _colors = Colors.primaries;

  @override
  Widget build(BuildContext context) => CustomScrollView(
        slivers: _colors
            .map(
              (color) => StackedListChild(
                minHeight: _minHeight,
                maxHeight: _tapped
                    ? (_colors.indexOf(color) == _colors.length - 1
                        ? MediaQuery.of(context).size.height
                        : 500)
                    : (_colors.indexOf(color) == _colors.length - 1
                        ? MediaQuery.of(context).size.height
                        : 120.0),
                pinned: true,
                child: GestureDetector(
                  child: Container(
                    color: _colors.indexOf(color) == 0
                        ? Colors.black
                        : _colors[_colors.indexOf(color) - 1],
                    child: Container(
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.vertical(
                            top: Radius.circular(_minHeight)),
                        color: color,
                      ),
                    ),
                  ),
                  onTap: () => setState(() {
                    _tapped = !_tapped;
                  }),
                  //print(_colors.indexOf(color).toString() + "Tapped"),
                ),
              ),
            )
            .toList(),
      );
}

class StackedListChild extends StatelessWidget {
  final double minHeight;
  final double maxHeight;
  final bool pinned;
  final bool floating;
  final Widget child;

  SliverPersistentHeaderDelegate get _delegate => _StackedListDelegate(
      minHeight: minHeight, maxHeight: maxHeight, child: child);

  const StackedListChild({
    Key key,
    @required this.minHeight,
    @required this.maxHeight,
    @required this.child,
    this.pinned = false,
    this.floating = false,
  })  : assert(child != null),
        assert(minHeight != null),
        assert(maxHeight != null),
        assert(pinned != null),
        assert(floating != null),
        super(key: key);

  @override
  Widget build(BuildContext context) => SliverPersistentHeader(
      key: key, pinned: pinned, floating: floating, delegate: _delegate);
}

class _StackedListDelegate extends SliverPersistentHeaderDelegate {
  final double minHeight;
  final double maxHeight;
  final Widget child;

  _StackedListDelegate({
    @required this.minHeight,
    @required this.maxHeight,
    @required this.child,
  });

  @override
  double get minExtent => minHeight;

  @override
  double get maxExtent => math.max(maxHeight, minHeight);

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return new SizedBox.expand(child: child);
  }

  @override
  bool shouldRebuild(_StackedListDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight ||
        child != oldDelegate.child;
  }
}

在动画中,被点击的小部件会到达顶部,只会被扩展。

最佳答案

要进行设计,您需要解决以下几个任务:
上面的卡有固定的位置。
卡片有透明的角,我们可以在那里看到以前的卡片。
如何解决?
通常,要执行第一个任务,需要创建自己的sliver并更改sliver几何体。观看关于长条的无聊节目:https://www.youtube.com/watch?v=Mz3kHQxBjGg&t=1606s
问题是sliverlist相当复杂,特别是如果你刚刚开始学习颤振。
所以我的解决方案是做一点黑客。
我们可以使用滚动位置得到顶部可见卡片的索引。
之后将其隐藏在sliver列表中,但在stack小部件中显示。
它也会有同样明显的影响。
在您的代码中,您使用额外的容器包装卡片,以使用前一张卡片的颜色作为背景色,但是当您需要显示每个卡片附近的两个连接符时,使用这种方法会遇到问题。解决方法是使用SizedOverflowBox。sizedOverflowBox小部件帮助您在具有可见溢出的小部件的位置呈现较大的小部件。
flutter - 我们怎么能在 flutter 中实现这样的东西呢?-LMLPHP

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

void main() => runApp(FlashCards());

class FlashCards extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: Text("Flash Cards"),
            backgroundColor: Colors.black,
          ),
          backgroundColor: Colors.black,
          body: StackedList()),
    );
  }
}

class StackedList extends StatefulWidget {
  @override
  _StackedListState createState() => _StackedListState();
}

const double closedCardSize = 100;
const double roundRadiusSize = 16;

class _StackedListState extends State<StackedList> {
  final List<Color> colors = Colors.primaries;
  ScrollController controller = ScrollController();
  int firstVisibleCardIndex = 0;

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  void initState() {
    controller.addListener(() {
      setState(
        () {
          firstVisibleCardIndex =
              (controller.offset / closedCardSize).floor();
        },
      );
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Container(
          height: closedCardSize + roundRadiusSize,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
            color: colors[firstVisibleCardIndex],
          ),
        ),
        CustomScrollView(
          physics: ClampingScrollPhysics(),
          controller: controller,
          slivers: [
            SliverList(
              delegate: SliverChildBuilderDelegate(
                  (context, index) => StackedListChild(
                        istTransparent: index <= firstVisibleCardIndex,
                        color: colors[index],
                        key: ObjectKey(colors[index]),
                      ),
                  childCount: colors.length - (firstVisibleCardIndex + 1)),
            )
          ],
        )
      ],
    );
  }
}


class StackedListChild extends StatelessWidget {
  const StackedListChild({
    Key key,
    this.color,
    this.istTransparent = false,
  }) : super(key: key);

  final Color color;
  final bool istTransparent;

  @override
  Widget build(BuildContext context) {
    if (istTransparent) {
      return SizedBox(
        height: closedCardSize,
      );
    }
    return Transform.translate(
      offset: Offset(0, roundRadiusSize / 2),
      child: SizedOverflowBox(
        size: Size(double.infinity, closedCardSize),
        child: Container(
          height: closedCardSize + roundRadiusSize,
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
              color: color,
            ),
          ),
        ),
      ),
    );
  }
}

希望这能引导你找到新的想法。
欢迎来到StackOverflow。γ

07-26 02:36