Flutter支架UI实现

jbose2ul  于 2023-03-09  发布在  Flutter
关注(0)|答案(1)|浏览(160)

我在一个应用程序上发现了这个,我想知道如何使用Flutter实现这个。
一开始我试着用PageView,但是从这个gif中你可以看到他们好像没有用,我想他们用的是listview,当它到达屏幕上的某个点时会添加动画。

s5a0g9ez

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,
    );
  }
}

相关问题