我在一个应用程序上发现了这个,我想知道如何使用Flutter实现这个。一开始我试着用PageView,但是从这个gif中你可以看到他们好像没有用,我想他们用的是listview,当它到达屏幕上的某个点时会添加动画。
s5a0g9ez1#
下面是我和你分享的代码,希望对你有所帮助。首先,我初始化断点和边距的数组,以避免在第一次构建时出现问题。然后,我根据每轮比赛的数量计算边距的值。我忘了考虑这段代码中的一些东西,那就是你有更多的比赛超过屏幕所能容纳的可能性,这可能会导致溢出错误。我建议你在使用代码时记住这一点。希望对你有帮助。问候。顺便说一句,如果我的英语不是最好的,很抱歉。
import 'package:flutter/material.dart'; const double _matcheHeight = 100; const double _matchWidth = 240; const double _matchRightPadding = 20; const double _minMargin = 5; class NFLStackOverflowPage extends StatelessWidget { const NFLStackOverflowPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const Scaffold( body: _PageContent( matchupsLenghtList: [6, 4, 2, 1], ), ); } } class _PageContent extends StatefulWidget { final List<int> matchupsLenghtList; const _PageContent({ Key? key, required this.matchupsLenghtList, }) : super(key: key); @override State<_PageContent> createState() => _PageContentState(); } class _PageContentState extends State<_PageContent> { List<double> breakpoints = []; List<double> verticalMargins = []; late ScrollController controller; @override void initState() { controller = ScrollController(); populateVerticalMargins(); populateBreakPoints(); WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { calculateVerticalMargins(); calculateBreakpoints(); }); controller.addListener(() { setState(() {}); }); super.initState(); } void populateVerticalMargins() { verticalMargins = widget.matchupsLenghtList.map((e) => 0.0).toList(); } void populateBreakPoints() { breakpoints = widget.matchupsLenghtList.map((e) => 0.0).toList(); } void calculateBreakpoints() { breakpoints = List.generate(widget.matchupsLenghtList.length, (index) { return index * (_matchWidth + _matchRightPadding); }); setState(() {}); } void calculateVerticalMargins() { verticalMargins = List.generate(widget.matchupsLenghtList.length, (index) { final matchLenght = widget.matchupsLenghtList[index]; final heightOfmatchups = matchLenght * _matcheHeight; final verticalMargin = (MediaQuery.of(context).size.height - heightOfmatchups) / (matchLenght + 1); // if matchups lenght is 4 we have 5 spaces that need to have this height return verticalMargin; }); setState(() {}); } @override Widget build(BuildContext context) { return CustomScrollView( controller: controller, scrollDirection: Axis.horizontal, slivers: [ SliverList( delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { final margin = _getMargin(index: index); return Container( margin: EdgeInsets.only(right: _matchRightPadding, bottom: margin), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( widget.matchupsLenghtList[index], (index) => Container( margin: EdgeInsets.only(top: margin), child: const MatchWidget(), ), ), ), ); }, childCount: widget.matchupsLenghtList.length, ), ), ], ); } double _getMargin({required int index}) { final initialMargin = verticalMargins[index]; double verticalMarginMultiplier = 1; if (index > 0) { final previousBreakpoint = breakpoints[index - 1]; //Example: 0 final currentBreakPoint = breakpoints[index]; //Example: 200 final currentScrollOffset = controller.offset; // Ex: 180 if (currentScrollOffset >= currentBreakPoint) { verticalMarginMultiplier = 0; } else if (currentScrollOffset <= previousBreakpoint) { verticalMarginMultiplier = 1; } else { final gap = currentBreakPoint - previousBreakpoint; // Ex 200 - 0 final currentExtend = currentScrollOffset - previousBreakpoint; // Ex: 180 - 0 verticalMarginMultiplier = 1 - currentExtend / gap; // Ex: 1 - 180 / 200 = 1 - 0.9 = 0.1 } } final marginAndverticalMarginMultiplier = initialMargin * verticalMarginMultiplier; // Ex: 40 * 0.1 = 4 double margin = initialMargin; //Set _minMargin value if marginAndverticalMarginMultiplier is less than _minMargin if (marginAndverticalMarginMultiplier >= _minMargin) { margin = marginAndverticalMarginMultiplier; } else if (initialMargin < _minMargin && initialMargin > 0) { margin = initialMargin; } else { margin = _minMargin; } return margin; } } class MatchWidget extends StatelessWidget { const MatchWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Container( height: _matcheHeight, width: _matchWidth, color: Colors.black, ); } }
1条答案
按热度按时间s5a0g9ez1#
下面是我和你分享的代码,希望对你有所帮助。首先,我初始化断点和边距的数组,以避免在第一次构建时出现问题。然后,我根据每轮比赛的数量计算边距的值。
我忘了考虑这段代码中的一些东西,那就是你有更多的比赛超过屏幕所能容纳的可能性,这可能会导致溢出错误。我建议你在使用代码时记住这一点。
希望对你有帮助。问候。顺便说一句,如果我的英语不是最好的,很抱歉。