如何在不重新构建其状态的情况下更改小部件的父级

huangapple go评论67阅读模式
英文:

How to change parent of widgets without rebuilding their states

问题

在Flutter中,我有如下的小部件:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) => Scaffold(
        body: OrientationBuilder(
          builder: (context, orientation) {
            const List<ColorfulBox> children = [ColorfulBox(), ColorfulBox()];

            return orientation == Orientation.portrait ? 
                const Row(children: children) : 
                const Column(children: children);            
          },
        ),
      );
}

class ColorfulBox extends StatefulWidget {
  const ColorfulBox({super.key});

  @override
  State<ColorfulBox> createState() => _ColorfulBoxState();
}

class _ColorfulBoxState extends State<ColorfulBox> {
  @override
  Widget build(BuildContext context) => Container(
        width: 100,
        height: 100,
        color: getRandomColor(),
      );
}

Color getRandomColor() {
  var generatedColor = Random().nextInt(Colors.primaries.length);
  return Colors.primaries[generatedColor];
}

目前,当我旋转设备时,ColorfulBox 的新状态会重新构建,导致颜色改变。

我想知道如何保持ColorfulBox的状态?
我尝试给ColorfulBox添加不同的键名,还尝试添加AutomaticKeepAliveClientMixin,但这两个想法都没有奏效。

英文:

In flutter, I have widgets like:

class _MyHomePageState extends State&lt;MyHomePage&gt; {
  @override
  Widget build(BuildContext context) =&gt; Scaffold(
        body: OrientationBuilder(
          builder: (context, orientation) {
            const List&lt;ColorfulBox&gt; children = [ColorfulBox(), ColorfulBox()];

            return orientation == Orientation.portrait ? 
                const Row(children: children) : 
                const Column(children: children);            
          },
        ),
      );
}

class ColorfulBox extends StatefulWidget {
  const ColorfulBox({super.key});

  @override
  State&lt;ColorfulBox&gt; createState() =&gt; _ColorfulBoxState();
}

class _ColorfulBoxState extends State&lt;ColorfulBox&gt; {
  @override
  Widget build(BuildContext context) =&gt; Container(
        width: 100,
        height: 100,
        color: getRandomColor(),
      );
}

Color getRandomColor() {
  var generatedColor = Random().nextInt(Colors.primaries.length);
  return Colors.primaries[generatedColor];
}

Currently when I rotate the device, new state of ColorfulBox will be build what causes color change.

I was wondering how can I keep ColorfulBox state?
I tried adding keys differently named to ColorfulBox and also adding AutomaticKeepAliveClientMixin but none of those two ideas worked.

答案1

得分: 1

事实上,您的小部件状态并未重新创建,而是再次执行了构建函数。

您需要在build方法之外调用getRandomColor()
使用以下代码:

class ColorfulBox extends StatefulWidget {
  const ColorfulBox({super.key});

  @override
  State<ColorfulBox> createState() => _ColorfulBoxState();
}

class _ColorfulBoxState extends State<ColorfulBox> {
  final _color = getRandomColor();
  @override
  Widget build(BuildContext context) => Container(
        width: 100,
        height: 100,
        color: _color,
      );
}

Color getRandomColor() {
  var generatedColor = Random().nextInt(Colors.primaries.length);
  return Colors.primaries[generatedColor];
}

更新:
另外,您需要将RowColumn小部件更改为Flex小部件,否则无法在不重新创建的情况下将小部件从列移动到行(或反之亦然)。
因此,请将

return orientation == Orientation.portrait
    ? Row(children: children)
    : Column(children: children);

更改为

return Flex(
  direction: orientation == Orientation.portrait ? Axis.horizontal : Axis.vertical,
  children: children,
);
英文:

In fact, your state of widget is not recreated, but the build function is executed again.

You need call getRandomColor() outside of the build method:
Use this code:

class ColorfulBox extends StatefulWidget {
  const ColorfulBox({super.key});

  @override
  State&lt;ColorfulBox&gt; createState() =&gt; _ColorfulBoxState();
}

class _ColorfulBoxState extends State&lt;ColorfulBox&gt; {
  final _color=getRandomColor();
  @override
  Widget build(BuildContext context) =&gt; Container(
        width: 100,
        height: 100,
        color: _color,
      );
}

Color getRandomColor() {
  var generatedColor = Random().nextInt(Colors.primaries.length);
  return Colors.primaries[generatedColor];
}

Update:
Also you need to change your Row and Column widget to Flex widget, you can't move widgets from Column to Row (or reverse) without recreating.
So, change

return orientation == Orientation.portrait
    ? Row(children: children)
    : Column(children: children);

To

return Flex(
  direction: orientation == Orientation.portrait ? Axis.horizontal : Axis.vertical,
  children: children,
);

答案2

得分: 1

你可以在定义子项列表时将颜色设置得更高一些:

import 'dart:math';

import 'package:flutter/material.dart';

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

Color _getRandomColor() =>
    Colors.primaries[Random().nextInt(Colors.primaries.length)];

class MyApp extends StatelessWidget {
  const MyApp({Key? key});

  @override
  Widget build(BuildContext context) => const MaterialApp(home: MyHomePage());
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key});

  @override
  Widget build(BuildContext context) {
    List<ColorfulBox> children = [
      ColorfulBox(key: const Key("1"), color: _getRandomColor()),
      ColorfulBox(key: const Key("2"), color: _getRandomColor()),
    ];

    return Scaffold(body: OrientationBuilder(
      builder: (BuildContext context, Orientation orientation) {
        return orientation == Orientation.portrait
            ? Row(children: children)
            : Column(children: children);
      },
    ));
  }
}

class ColorfulBox extends StatefulWidget {
  const ColorfulBox({Key? key, required this.color});
  final Color color;
  @override
  State<ColorfulBox> createState() => _ColorfulBoxState();
}

class _ColorfulBoxState extends State<ColorfulBox> {
  @override
  Widget build(BuildContext context) {
    print("build ${widget.key}");
    return Container(
      width: 100,
      height: 100,
      color: widget.color,
    );
  }
}
英文:

You could set the colors higher up, when you define the children List:

import &#39;dart:math&#39;;

import &#39;package:flutter/material.dart&#39;;

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

Color _getRandomColor() =&gt;
    Colors.primaries[Random().nextInt(Colors.primaries.length)];

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) =&gt; const MaterialApp(home: MyHomePage());
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    List&lt;ColorfulBox&gt; children = [
      ColorfulBox(key: Key(&quot;1&quot;), color: _getRandomColor()),
      ColorfulBox(key: Key(&quot;2&quot;), color: _getRandomColor()),
    ];

    return Scaffold(body: OrientationBuilder(
      builder: (BuildContext context, Orientation orientation) {
        return orientation == Orientation.portrait
            ? Row(children: children)
            : Column(children: children);
      },
    ));
  }
}

class ColorfulBox extends StatefulWidget {
  const ColorfulBox({super.key, required this.color});
  final Color color;
  @override
  State&lt;ColorfulBox&gt; createState() =&gt; _ColorfulBoxState();
}

class _ColorfulBoxState extends State&lt;ColorfulBox&gt; {
  @override
  Widget build(BuildContext context) {
    print(&quot;build ${widget.key}&quot;);
    return Container(
      width: 100,
      height: 100,
      color: widget.color,
    );
  }
}

huangapple
  • 本文由 发表于 2023年7月17日 20:37:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76704524.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定