dart 为什么Flutter PageView在setState后重置为页面0

sczxawaw  于 2024-01-03  发布在  Flutter
关注(0)|答案(2)|浏览(147)

在显示的第一页上方,我显示了一条消息,用户可以向左滑动以转到下一页。在onPageChanged中,我设置了一个bool来关闭消息并调用setState。当我滑动到第1页时,在调用setState的那一刻,页面重置为第0页。
当我删除条件文本时,页面正常滑动。
DartPad gist:https://dartpad.dev/?id=e30a98e4bc531d9cdc93780b6e47f972
这是一个bug还是我错过了什么?
完整的示例代码如下:

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

void main() {
  runApp(PageViewTestScreen());
}

class PageViewTestScreen extends StatefulWidget {
  PageViewTestScreen({super.key});

  @override
  State<PageViewTestScreen> createState() => _PageViewTestScreenState();
}

class _PageViewTestScreenState extends State<PageViewTestScreen> {
  PageController pageController = PageController(initialPage: 0);
  bool lastPage = false;
  bool userHasSlided = false;
  int numberOfPages = 5;

  @override
  void initState() {
    super.initState();
  }

  void onPageChanged(int index) {
    userHasSlided = true;

    lastPage = index == levensgebieden.length-1;
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        floatingActionButton: lastPage
            ? FloatingActionButton(
                onPressed: () {},
                child: Icon(Icons.check),
              )
            : null,
        appBar: AppBar(
          foregroundColor: Colors.white,
          title: const Text("PageView bug?"),
        ),
        body: ListView(
          children: [
            const Text("Here are some pages"),
            const SizedBox(height: 6),
            if (!userHasSlided) const Text("Swipe left to continue."),
            SizedBox(
              height: 500,
              child: PageView(
                scrollBehavior: const ScrollBehavior().copyWith(dragDevices: {
                  PointerDeviceKind.touch,
                  PointerDeviceKind.mouse,
                  PointerDeviceKind.stylus,
                }),
                controller: pageController,
                onPageChanged: (int index) {
                  onPageChanged(index);
                },
                children: [
                  for (int i = 0; i < 5; i++) card(i),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }

  Widget card(int index) {
    return Card(
      child: SizedBox(
          height: 500, width: 200, child: Center(child: Text("Page: $index"))),
    );
  }
}

字符串

csbfibhn

csbfibhn1#

对于这种情况,提供key有助于元素树。

SizedBox(
  key: const Key("my_pageView"),
  height: 500,
  child: PageView(

字符串
有关Keys.的更多信息

quhf5bfb

quhf5bfb2#

这是意料之中的,因为userHasSlided改变的那一刻,ListView的子元素也改变了,这触发了一个小部件重建。由于PageView不是一个常量,它也被重建。重建中断了用户已经完成的滑动进度,因此将页面重置为0。
您可以尝试在其他地方(ListView之外)添加条件大小写,也许在AppBar中,并删除ListView中的条件文本,您会注意到PageView将按预期工作。这是因为PageView没有被重建。

相关问题