在Flutter中,如何解决“ AnimatedCrossFade”的低效设计?

时间:2018-08-08 03:25:16

标签: flutter flutter-layout flutter-animation

AnimatedCrossFade的一个问题是,即使只显示两个孩子,也必须同时提供两个孩子。

如果这些孩子中的一个(或两个)既复杂又沉重,这是没有效率的。

我试图提供一个Builder,像这样:

AnimatedCrossFade(
    firstChild: widget1,
    secondChild: Builder(builder: widget2builder),
    duration: const Duration(milliseconds: 500),
    crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
),

var widget2builder = (context) {
  print("Building widget 2");
  return Container(),
  );
};

但是,即使第一个窗口小部件正在显示,因此它也会立即打印 Building widget 2 ,因此根本不需要窗口小部件2。

这是一个完整的,可运行的示例:

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  bool toggle;

  @override
  void initState() {
    super.initState();
    toggle = true;
  }

  @override
  Widget build(BuildContext context) {
    var toggleButton = Padding(
      padding: const EdgeInsets.all(8.0),
      child: MaterialButton(
        child: const Text("Toggle"),
        color: Colors.grey,
        onPressed: () {
          setState(() {
            toggle = !toggle;
          });
        },
      ),
    );

    var widget1 = Container(
      key: UniqueKey(),
      color: Colors.blue,
      width: 200.0,
      child: const Text(
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt "
            "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
            "ullamco laboris nisi ut aliquip ex ea commodo consequat.",
      ),
    );

    var widget2builder = (context) {
      print("Building widget 2.");
      return Container(
        key: UniqueKey(),
        color: Colors.red,
        width: 200.0,
        child: const Text(
          "I am ready for my closeup.",
        ),
      );
    };

    return MaterialApp(
      home: Material(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            toggleButton,
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                const Text("Some text above."),
                AnimatedCrossFade(
                  firstChild: widget1,
                  secondChild: Builder(builder: widget2builder),
                  duration: const Duration(milliseconds: 500),
                  crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
                ),
                const Text("Some text below."),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

如果运行此命令,则会看到 Building widget 2 已打印到控制台,但正在显示的是小部件1。

我的问题:

  • AnimatedCrossFade正在构建不使用的小部件吗?

  • 如何预防此问题并有效使用AnimatedCrossFade

2 个答案:

答案 0 :(得分:2)

我想补充一下Rémi的答案,在问了这个问题后的某个时候,我发布了一个名为AnimatedSizeAndFade的软件包来解决它:

https://pub.dev/packages/animated_size_and_fade

与其他类似小部件相比如何?

  • 使用AnimatedCrossFade,您必须同时保留firstChild和secondChild,而AnimatedSizeAndFade则不需要。

  • 使用AnimatedSwitcher,您可以简单地更改其子级,但随后只会设置淡入淡出的动画效果,而不是大小。

  • AnimatedContainer也不起作用,除非您事先知道孩子的大小。

答案 1 :(得分:1)

这是预期的行为。

如飞镖团队所述,您应该期望随时调用void TableDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { qDebug() << index.row() << index.column(); TableDataRow::Type type = static_cast<TableDataRow::Type>( index.data( Qt::UserRole ).toInt() ); QString text = index.data( Qt::DisplayRole ).toString(); int row = index.row(); if ( option.state & QStyle::State_MouseOver ) { if ( type == TableDataRow::Type::Data ) { painter->fillRect( QRect( 0, option.rect.topLeft().y(), option.rect.width()*numberOfColumns, option.rect.height() ), QColor( 249, 126, 18 ) ); for ( int i = 0; i < numberOfColumns; i++ ) { QModelIndex indexOfRow = index.sibling( row, i ); painter->setPen( Qt::white ); painter->drawText( option.rect, Qt::AlignVCenter | Qt::TextWordWrap, text ); } } } } 方法。 build被设计为便宜且没有副作用。

构建窗口小部件的事实并不意味着它已在屏幕上呈现。 build的不透明度为0实际上会缩短绘画过程(并且在完全不透明时进行其他优化)。


如果这引起问题,那么您应该改用AnimatedSwitcher来替换子元素时播放动画。