我在 Flutter 中将新项目插入反向 ListView 的底部时遇到问题

问题描述 投票:0回答:1

我有这个简单的有状态小部件:


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

  @override
  State<SomeListWidget> createState() => _SomeListWidgetState();
}

class _SomeListWidgetState extends State<SomeListWidget> {
  List<Color> colors = [
    Colors.red,
    Colors.green,
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: colors.length,
              reverse: true,
              itemBuilder: (context, index) {
                return ColorTransitionBox(
                  targetColor: colors[index],
                );
              },
            ),
          ),
          ElevatedButton(
            onPressed: () {
              setState(() {
                final rnd = Random();
                final color = Color.fromARGB(
                    255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
                colors.insert(0, color);
              });
            },
            child: Text('Add color'),
          ),
        ],
      ),
    );
  }
}

ColorTransitionBox 小部件将其颜色从白色线性更改为目标颜色:

class ColorTransitionBox extends StatefulWidget {
  final Color targetColor;

  const ColorTransitionBox({Key? key, required this.targetColor})
      : super(key: key);

  @override
  State<ColorTransitionBox> createState() => _ColorTransitionBoxState();
}

class _ColorTransitionBoxState extends State<ColorTransitionBox> {
  Color _currentColor = Colors.white;

  @override
  void initState() {
    super.initState();
    // Start the color transition after the first frame is rendered
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        _currentColor = widget.targetColor;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      duration: const Duration(seconds: 1),
      curve: Curves.linear, // Linear animation
      color: _currentColor,
      width: 100, // Example width
      height: 100, // Example height
      child: Center(
        child: Text(
          'Color Box',
          style: TextStyle(
            color: _currentColor == Colors.white ? Colors.black : Colors.white,
          ),
        ),
      ),
    );
  }
}

当我单击“添加颜色”时,我希望底部出现一个新框,在 1 秒内将颜色从白色线性更改为随机。但是当我单击时,顶部会出现一个框,其颜色始终与列表中最后一项的颜色相匹配(在本例中为绿色)。我需要反转 ListView 并且新的小部件出现在底部。

我尝试使用UniqueKey

          Expanded(
            child: ListView.builder(
              itemCount: colors.length,
              reverse: true,
              itemBuilder: (context, index) {
                return ColorTransitionBox(
                  key: UniqueKey(),
                  targetColor: colors[index],
                );
              },
            ),
          ),

它有效,但现在当我添加一个新元素时,所有其他元素再次开始转换 我也使用 ValueKey(colors[index]),但结果是一样的。

flutter dart listview
1个回答
0
投票

这可以解决问题:

  @override
  void didUpdateWidget(covariant ColorTransitionBox oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (widget.targetColor != oldWidget.targetColor) {
      currentColor = widget.targetColor;
    } // to sync the newly added dynamic color
  }

这是针对您的问题的重构代码片段解决方案:

import 'dart:math';

import 'package:flutter/material.dart';

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

  @override
  State<SomeListWidget> createState() => _SomeListWidgetState();
}

class _SomeListWidgetState extends State<SomeListWidget> {
  List<Color> colors = [
    Colors.red,
    Colors.green,
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: colors.length,
              reverse: true,
              itemBuilder: (context, index) {
                return ColorTransitionBox(
                  targetColor: colors[index],
                );
              },
            ),
          ),
          ElevatedButton(
            onPressed: () {
              setState(() {
                final rnd = Random();
                final color = Color.fromARGB(
                    255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
                colors.insert(0, color);
              });
            },
            child: Text('Add color'),
          ),
        ],
      ),
    );
  }
}

class ColorTransitionBox extends StatefulWidget {
  final Color? targetColor;

  const ColorTransitionBox({super.key, required this.targetColor});

  @override
  State<ColorTransitionBox> createState() => _ColorTransitionBoxState();
}

class _ColorTransitionBoxState extends State<ColorTransitionBox> {
  Color? currentColor;

  @override
  void initState() {
    super.initState();
    // Start the color transition after the first frame is rendered
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        setState(() {
          currentColor = widget.targetColor;
        });
      }
    }); // still needed this to initialize the color from the parent widget
  }

  @override
  void didUpdateWidget(covariant ColorTransitionBox oldWidget) {
    super.didUpdateWidget(oldWidget);

    if (widget.targetColor != oldWidget.targetColor) {
      currentColor = widget.targetColor;
    } // to sync the newly added dynamic color
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      duration: const Duration(seconds: 1),
      curve: Curves.linear, // Linear animation
      color: currentColor,
      width: 100, // Example width
      height: 100, // Example height
      child: Center(
        child: Text(
          'Color Box',
          style: TextStyle(
            color: currentColor == Colors.white ? Colors.black : Colors.white,
          ),
        ),
      ),
    );
  }
}

希望对你有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.