Flutter使Perspective Page View无限循环

Chr*_*ris 5 dart flutter flutter-pageview

我实现了这样perspective_page_view的。我将代码更新到新的 Flutter 版本,一切正常。

问题是我希望它PageView有一个无限循环

我尝试了在这个问题上找到的多种不同的解决方案,但没有一个有效。他们都搞乱了我的观点。

我觉得这应该是可能的,但我无法想出解决方案。为每一次帮助感到高兴!如果您需要更多信息,请告诉我!

最小可生产示例:

我的Scaffold

class ProjectsViewState extends State<ProjectsView>
    with TickerProviderStateMixin {
  late PageViewHolder holder;

  late PageController _controller;
  double fraction = 0.50;

  @override
  void initState() {
    super.initState();
    holder = PageViewHolder(value: 2.0);
    _controller = PageController(initialPage: 2, viewportFraction: fraction);
    _controller.addListener(() {
      holder.setValue(_controller.page);
    });
  }

  int currentPage = 2;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: ChangeNotifierProvider<PageViewHolder>.value(
          value: holder,
          child: Flexible(
            child: PageView.builder(
              controller: _controller,
              onPageChanged: (value) {
                setState(() {
                  currentPage = value;
                });
              },
              itemCount: projectsCounter,
              physics: const BouncingScrollPhysics(),
              itemBuilder: (context, index) {
                return ProjectsGalleryView(
                  number: index.toDouble(),
                  fraction: fraction,
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

pageView

class ProjectsGalleryView extends StatefulWidget {
  final double number;
  final double fraction;

  const ProjectsGalleryView(
      {super.key, required this.number, required this.fraction});

  @override
  State<ProjectsGalleryView> createState() => _ProjectsGalleryViewState();
}

class _ProjectsGalleryViewState extends State<ProjectsGalleryView>
    with SingleTickerProviderStateMixin {
  @override
  Widget build(BuildContext context) {
    double value = Provider.of<PageViewHolder>(context).value;
    double diff = (widget.number - value);

    //Matrix for Elements
    final Matrix4 pvMatrix = Matrix4.identity()
      ..setEntry(3, 3, 1 / 0.8) // Increasing Scale by 80%
      // ..setEntry(1, 1, widget.fraction) // Changing Scale Along Y Axis
      ..setEntry(3, 0, 0.003 * -diff); // Changing Perspective Along X Axis

    return Transform(
      transform: pvMatrix,
      alignment: FractionalOffset.center,
      child: Column(
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 0),
            child: SizedBox(
              height: 200,
              width: 200,
              child: Container(
                decoration: BoxDecoration(
                  color: Colors.redAccent,
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
            ),
          ),
          if (diff <= 1.0 && diff >= -1.0) ...[
            AnimatedOpacity(
              duration: const Duration(milliseconds: 100),
              opacity: 1 - diff.abs(),
              child: const Padding(
                padding: EdgeInsets.symmetric(
                  horizontal: 15,
                  vertical: 20,
                ),
                child: Text(
                  'A Text with animated opacity',
                ),
              ),
            ),
          ]
        ],
      ),
    );
  }
Run Code Online (Sandbox Code Playgroud)

HW *_*Kim 1

好吧,如果您希望左侧的滚动也平滑。你只需要任意设定LARGE NUMBER一个起点,这样就可以感觉到INFINITE(像9万亿这样的大数字)。但是,它不会无限期地滚动。

  1. 设置一些大数字(例如const largeInt = 9223372036854;:)
  2. 修改你的initState喜欢如下

@override
void initState() {
  super.initState();
  holder = PageViewHolder(value: largeInt.toDouble());
  _controller = PageController(
    initialPage: largeInt,
    viewportFraction: fraction,
  );
  _controller.addListener(() {
    holder.setValue(_controller.page);
  });
}
Run Code Online (Sandbox Code Playgroud)

以及完整的代码ProjectView

const largeInt = 9223372036854;

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

  @override
  ProjectsViewState createState() => ProjectsViewState();
}

class ProjectsViewState extends State<ProjectsView>
    with TickerProviderStateMixin {
  late PageViewHolder holder;

  late PageController _controller;
  double fraction = 0.50;

  @override
  void initState() {
    super.initState();
    holder = PageViewHolder(value: largeInt.toDouble());
    _controller = PageController(
      initialPage: largeInt,
      viewportFraction: fraction,
    );
    _controller.addListener(() {
      holder.setValue(_controller.page);
    });
  }

  int _currentPage = 2;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: ChangeNotifierProvider<PageViewHolder>.value(
            value: holder,
            child: Column(
              children: [
                Flexible(
                  child: PageView.builder(
                    controller: _controller,
                    onPageChanged: (value) {
                      setState(() => _currentPage = value);
                    },
                    physics: const BouncingScrollPhysics(),
                    itemBuilder: (context, index) {
                      return ProjectsGalleryView(
                        number: index.toDouble(),
                        fraction: fraction,
                      );
                    },
                  ),
                ),
              ],
            )),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

// 之前的答案

TL;DR 这不是一个完美的解决方案,但要在左侧无限滚动jumpToPage_controller.addListener

首先,不要包含itemCountPageview.builder或将其设置为null.

然而,即使你设置itemCount为,它仍然会在isnull时结束。index0

因此,在initState初始化后添加以下内容PageController

_controller.addListener(() {
  holder.setValue(_controller.page);
  final page = _controller.page;
  if (page == null) return;
  if (page < 2.01 && page > 1.99) {
    _controller.jumpToPage(10);
  }
});
Run Code Online (Sandbox Code Playgroud)

通过在 1.99 和 2.01 之间添加_controller.jumpToPage(10)when ,将再次将页面设置为 10。_controller.page_pageController

我在 中添加这个的原因_controller.addListener是,如果你把它放进去onPageChanged,它会非常糟糕,因为返回的valueint.

然而,尽管我使用了双倍来最小化影响,但当滚动得非常快时,它仍然会有点卡顿,如果它非常快,它有可能无法工作。但是,这对于正常的逐页滚动始终有效。

您的ProjectView Widget.

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

  @override
  ProjectsViewState createState() => ProjectsViewState();
}

class ProjectsViewState extends State<ProjectsView>
    with TickerProviderStateMixin {
  late PageViewHolder holder;

  late PageController _controller;
  double fraction = 0.50;

  @override
  void initState() {
    super.initState();
    holder = PageViewHolder(value: 2.0);
    _controller = PageController(initialPage: 2, viewportFraction: fraction);
    _controller.addListener(() {
      holder.setValue(_controller.page);
      final page = _controller.page;
      if (page == null) return;
      if (page < 2.01 && page > 1.99) {
        _controller.jumpToPage(10);
      }
    });
  }

  int currentPage = 2;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: ChangeNotifierProvider<PageViewHolder>.value(
          value: holder,
          child: Flexible(
            child: PageView.builder(
              controller: _controller,
              onPageChanged: (value) {
                setState(() => currentPage = value);
              },
              physics: const BouncingScrollPhysics(),
              itemBuilder: (context, index) {
                return ProjectsGalleryView(
                  number: index.toDouble(),
                  fraction: fraction,
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)