我想在颤栗中建造这样的东西。
我尝试过使用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小部件帮助您在具有可见溢出的小部件的位置呈现较大的小部件。
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。γ