Flutter: la página con SingleTickerProviderStateMixin provoca una compilación innecesaria

CorePress2024-01-25  10

Tengo este problema con el enlace de github. Lo que sucede es que si un widget usa TickerProviderStateMixin, se reconstruye cuando ocurre una navegación de página. Tengo una página muy compleja y reconstruir toda la página provoca un bloqueo de la interfaz de usuario en la navegación de la página. Si no reconstruyo entonces todo estará bien, sin problemas. ¿Hay una solución para esto? ¿Me parece que se trata de algún tipo de error interno o de un comportamiento inesperado?

Ejemplo:

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: PageA(title: 'Flutter Demo Home Page'),
    );
  }
}

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

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

class _PageAState extends State<PageA>
    with SingleTickerProviderStateMixin {

  TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController = TabController(length: 2, vsync: this);
  }

  void toPageB() {
    //tabController.animateTo(1);
    Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
      return PageB();
    }));
  }

  @override
  Widget build(BuildContext context) {
    print("Page A");
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: TabBar(
          tabs: [
            Text(
              "Tab A",
              style: Theme.of(context).textTheme.bodyText1,
            ),
            Text(
              "Tab B",
              style: Theme.of(context).textTheme.bodyText1,
            )
          ],
          controller: tabController,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: toPageB,
        child: Icon(Icons.add),
      ),
    );
  }
}

class PageB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("Page B");
    return Scaffold(
        appBar: AppBar(
          title: Text("Page A"),
        ),
        body: Container(
          child: Center(
            child: Text("Page A"),
          ),
        ));
  }
}

Incluso si no usas TickerProviderStateMixin, la reconstrucción puede realizarse y eso es fácil.st Flutter forma de hacer las cosas. No puedes hacer mucho al respecto.

- iDecode

31 de marzo de 2021 a las 16:34

Bueno, supongo que estoy decepcionado de que Flutter no haya podido sostener la estructura de mi árbol. Tenía alrededor de 400 contenedores y algunos objetos animados.

- chico cs

31/03/2021 a las 17:10

¿400 contenedores en una lista o columna o en otro lugar?

- iDecode

31 de marzo de 2021 a las 17:32

Dentro de una vista de página

- chico cs

31/03/2021 a las 18:20

Bien, ¿estás usando PageView.builder o algún otro constructor?

- iDecode

1 de abril de 2021 a las 5:13



------------------------------------

@override
  // ignore: must_call_super
  void didChangeDependencies() {}

simplemente agregue el código para evitar la reconstrucción. No conozco el efecto secundario, pero este recorrido funciona para mi aplicación.



------------------------------------

Esta es la solución que usé antes.

Cambiar tu página Un me gusta

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

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

class _PageAState extends State<PageA> {
  TabController tabController;

  // @override
  // void initState() {
  //   super.initState();
  //   tabController = TabController(length: 2, vsync: this);
  // }

  void toPageB() {
    tabController.animateTo(1);
    Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) {
      return PageB();
    }));
  }

  @override
  Widget build(BuildContext context) {
    print("Page A");
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: CustomTabBar(
          tabs: [
            Text(
              "Tab A",
              style: Theme.of(context).textTheme.bodyText1,
            ),
            Text(
              "Tab B",
              style: Theme.of(context).textTheme.bodyText1,
            )
          ],
          controller: (controller) {
            tabController = controller;
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: toPageB,
        child: Icon(Icons.add),
      ),
    );
  }
}

Y agrega una nueva clase CustomTabBar

class CustomTabBar extends StatefulWidget {
  const CustomTabBar({
    this.controller,
    this.tabs,
    Key? key,
  }) : super(key: key);
  final Function(TabController)? controller;
  final List<Widget>? tabs;

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

class _CustomTabBarState extends State<CustomTabBar>
    with SingleTickerProviderStateMixin {
  late TabController tabController;

  @override
  void initState() {
    super.initState();
    tabController =
        TabController(length: widget.tabs?.length ?? 0, vsync: this);
    if (widget.controller != null) {
      widget.controller!(tabController);
    }
  }

  @override
  void dispose() {
    tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TabBar(
      tabs: widget.tabs ?? [],
      controller: tabController,
    );
  }
}

Debería solucionar el problema de que la página A se reconstruya

respondido el

1 de abril de 2021 a las 2:29

Sam Chan

Sam Chan

1.693

5

5 insignias de plata

14

14 insignias de bronce

7

Muchas gracias por compartir esto. No pude entender, ¿cómo ayuda esto con la reconstrucción? ¿Podrías dar más contexto?

- chico cs

1 de abril de 2021 a las 2:43

En primer lugar, es necesario mantener la animación, por lo que necesitas SingleTickerProviderStateMixi.norte. Como sabemos, SingleTickerProviderStateMixin llamará a la interfaz de usuario para actualizar. Por lo tanto, cree una CustomTabBar secundaria y realice todos los cambios en la interfaz de usuario dentro de la CustomTabBar cuando se reproduzca la animación. Puede ver que solo CustomTabBar usa SingleTickerProviderStateMixin y cuando está en initState pasará el tabController a la página A. Cuando la página A llama al tabController para reproducir una animación, en realidad permite que la CustomTabBar secundaria se reconstruya

- Sam Chan

1 de abril de 2021 a las 2:52

esto restringe la capacidad de utilizar AnimationController en PageA

- chico cs

2 de abril de 2021 a las 16:12

A menos que tengas otro widget de animación en la página A, la solución es la misma. Haga que el widget de animación se convierta en un nuevo widget stareful personalizado y pase el controlador de regreso a la página A en su estado inicial

- Sam Chan

3 de abril de 2021 a las 1:42

Así que básicamente lo que estás sugiriendo es que¿Tiene un widget con TickerProviderStateMixin y crea múltiples controladores de animación y los pasa a subwidgets secundarios? Lo siento, me cuesta entender tu solución :(

- chico cs

3 de abril de 2021 a las 1:47

randomThread
sql: limita los resultados devueltos por MySQL join a 1Rust - sin(), cos(), log10() (flotante) no encontrado para el objetivo thumbv7em-none-eabihfAnálisis en Python Pandas: distinguir pulgadas versus centímetrosjavascript - El bot de Discord produce un error Error[TOKEN_INVALID] Se proporcionó un token no válidophp - La relación de muchos a muchos de Laravel 8 no funciona (no se generan errores)Cambiar el tamaño del tamaño de la lista serializable (Unity C#)javascript: página html local con contenido de archivo localLaravel: cómo restar los recuentos de dos camposjavascript - ¿Cómo llamar a un php con parámetro de un