如何防止重建PageView的StatelessWidget子级

时间:2019-08-29 06:32:01

标签: flutter

我已经创建了一个简单的PageView应用来测试多个页面。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    final firstPage = FirstPage(key: Key("FirstPage"));
    final secondPage = SecondPage(key: Key("SecondPage"));

    debugPrint("_MyHomePageState.build");
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: PageView(
        children: <Widget>[
          firstPage,
          secondPage,
        ],
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    debugPrint("FirstPage.build");
    return Container(
      child: Center(
        child: Text("First Page"),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    debugPrint("SecondPage.build");
    return Container(
      child: Center(
        child: Text("Second Page"),
      ),
    );
  }
}

即使 _MyHomePageState.build 仅显示一次, FirstPage.build <每次页面更改时都会打印em> SecondPage.build

我想防止不必要的页面绘制,该怎么做?

3 个答案:

答案 0 :(得分:3)

您可以通过使用来实现

1. const 关键字

  • 让您的小部件接受const

    class FirstPage 扩展 StatelessWidget { const FirstPage({Key key}) : super(key: key);

    @override
    Widget build(BuildContext context) {
      debugPrint("FirstPage.build");
      return Container(
        child: Center(
          child: Text("First Page"),
        ),
      );
    }
    

    }

  • 并使用 const 关键字调用它:

      return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: PageView(
          children: <Widget>[
            const firstPage(),
            const secondPage(),
          ],
        ),
      );
    

2. AutomaticKeepAliveClientMixin

  • 将您的 StatelessWidget 转换为 StatefullWidget
class FirstPage extends StatefulWidget {
  FirstPage({Key key}) : super(key: key);

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

class _FirstPageState extends State<FirstPage> {
  @override
  Widget build(BuildContext context) {
    debugPrint("FirstPage.build");
    return Container(
      child: Center(
        child: Text("First Page"),
      ),
    );
  }
}
  • AutomaticKeepAliveClientMixin 创建的 StatefullWidget 上扩展 State
class _FirstPageState extends State<FirstPage> with AutomaticKeepAliveClientMixin {
  • super 方法上调用 build
@override
  Widget build(BuildContext context) {
    super.build(context);
    debugPrint("FirstPage.build");
    return Container(
      child: Center(
        child: Text("First Page"),
      ),
    );
  }
  • 使用 wantKeepAlive 返回值覆盖 true getter。
  @override
  bool get wantKeepAlive => true;

然后你的小部件树不会处理这个小部件,所以它不会一遍又一遍地重建。

代码示例:

class FirstPage extends StatefulWidget {
  FirstPage({Key key}) : super(key: key);

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

class _FirstPageState extends State<FirstPage>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    debugPrint("FirstPage.build");
    return Container(
      child: Center(
        child: Text("First Page"),
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

3. MVVM 架构与您喜欢的任何 State-management 解决方案

它会在远离 ViewModelView 上保存您的状态,因此您的 UI 可以随时自行重建,而无需担心您的 State,因为 ViewModel 是还是一样。

答案 1 :(得分:1)

您应该始终想像,每秒要对您的build()方法(用于StatefulWidget和StatelessWidget)进行60次调用,因此它们应该是简单且幂等的。其他所有内容都应移入StatefulWidget initState()和朋友中。

答案 2 :(得分:-1)

很简单!

pageController可以为您提供帮助。

只需在您的_MyHomePageState

声明final pageController = PageController(keepPage: false);

在您的PageView

PageView(
        controller: pageController,
        children: <Widget>[
          firstPage,
          secondPage,
        ],
      )

祝你好运。