android 在Flutter中如何使PageView滚动得更快?动画似乎很慢,内部的ListView无法响应我的垂直手势

8xiog9wr  于 2023-04-28  发布在  Android
关注(0)|答案(3)|浏览(195)

您可以在video中查看详细信息
我不知道如何解决这个问题。与Android Native ViewPager相比,Flutter中PageView的动画似乎较慢,用户只需等待这个缓慢的动画完全停止,就可以拖动内部的ListView。我觉得用户体验比原生Android ViewPager差。希望有一个完美的解决方案。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/reactive_page_view/reactive_page_view.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Page(),
    );
  }
}

class Page extends StatefulWidget {
  @override
  _PageState createState() => _PageState();
}

PageView view;

class _PageState extends State<Page> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CupertinoNavigationBar(
        middle: Text("Demo"),
      ),
      body: PageView.builder(
          physics: BouncingScrollPhysics(),
          itemCount: 3,
          itemBuilder: (context, index) {
            return ItemPage();
          }),
    );
  }
}

class ItemPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        physics: BouncingScrollPhysics(),
        itemCount: 30,
        itemBuilder: (context, index) {
          return Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text('这是第$index', style: TextStyle(fontSize: 30)),
          );
        });
  }
}
hvvq6cgz

hvvq6cgz1#

可以控制滚动动画的常规物理特性。

PageView(
  physics: CustomPageViewScrollPhysics(),

控制滚动行为:

class CustomPageViewScrollPhysics extends ScrollPhysics {
  const CustomPageViewScrollPhysics({ScrollPhysics? parent})
      : super(parent: parent);

  @override
  CustomPageViewScrollPhysics applyTo(ScrollPhysics? ancestor) {
    return CustomPageViewScrollPhysics(parent: buildParent(ancestor)!);
  }

  @override
  SpringDescription get spring => const SpringDescription(
        mass: 50,
        stiffness: 100,
        damping: 0.8,
      );
}

你也应该能够用质量、刚度、阻尼来计算持续时间,但我相信有这些选项更适合你的问题。Source

qfe3c7zg

qfe3c7zg2#

你可以定义你自己的PageController示例并使用它的方法nextPage()和previousPage()。它们有“duration”参数来控制页面视图滚动的速度。

final PageController controller = PageController(
    viewportFraction: 0.9,
  );

  void nextPage() async {
    await controller.nextPage(
      duration: Duration(milliseconds: 200),
      curve: Curves.easeOut,
    );
  }

  void prevPage() async {
    await controller.previousPage(
      duration: Duration(milliseconds: 200),
      curve: Curves.easeOut,
    );
  }

然后将此控制器应用于页面视图:

return PageView.builder(
      physics: NeverScrollableScrollPhysics(),
      controller: controller,
      ...
    );

main.dart的完整代码:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyPageViewExample(),
    );
  }
}

class MyPageViewExample extends StatelessWidget {
  MyPageViewExample({Key key}) : super(key: key);

  final PageController controller = PageController(
    viewportFraction: 0.9,
  );

  void nextPage() async {
    await controller.nextPage(
      duration: Duration(milliseconds: 200),
      curve: Curves.easeOut,
    );
  }

  void prevPage() async {
    await controller.previousPage(
      duration: Duration(milliseconds: 200),
      curve: Curves.easeOut,
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          Container(
            color: Colors.grey[100],
          ),
          Padding(
            padding: EdgeInsets.only(top: 20.0 + MediaQuery.of(context).padding.top, bottom: 20.0),
            child: _buildCarousel(context),
          ),
        ],
      ),
    );
  }

  Widget _buildCarousel(BuildContext context) {
    return PageView.builder(
      physics: NeverScrollableScrollPhysics(),
      controller: controller,
      scrollDirection: Axis.horizontal,
      itemBuilder: (BuildContext context, int itemIndex) {
        return _buildItem(context, itemIndex);
      },
      itemCount: 5,
    );
  }

  Widget _buildItem(BuildContext context, int itemIndex) {
    return Padding(
      padding: EdgeInsets.only(left: 4.0, top: 10.0, right: 4.0, bottom: 10.0),
      child: GestureDetector(
        onPanUpdate: (details) {
          if (details.delta.dx < 0) {
            nextPage();
          }
          if (details.delta.dx > 0) {
            prevPage();
          }
        },
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.all(Radius.circular(35.0)),
          ),
          child: Center(
            child: Text(
              'Item ' + (itemIndex + 1).toString(),
            ),
          ),
        ),
      ),
    );
  }
}
xytpbqjk

xytpbqjk3#

我用NotificationListener Package 了页面视图并禁用了pageSnapping。当NotificationListener被调用时,我会查找最可见的元素并滚动到它

return NotificationListener<ScrollEndNotification>(
      onNotification: (notification) {
        _scrollToCurrentPage(pageController);
        return true;
      },
      child: PageView.builder(
        //page reload is pretty quick, we don't need to keep it in memory
        controller: pageController,
        itemBuilder: (context, index) => ViewItem(pages[index]),
        itemCount: pages.length,
        pageSnapping: false,
      ),
    );
  }

void _scrollToCurrentPage(PageController pageController) {
   WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      pageController.page?.round().let((it) => pageController.animateToPage(
            it,
            duration: RConsts.snapPageAnimationDuration,
            curve: Curves.easeInOut,
          ));
    });
  }

在那之后,我可以像列表视图一样快地滚动页面。我假设你也可以用水平列表视图来做。

相关问题