Skip to content

Fade in/out not working with CachedNetworkImage on first launch but will work afterwards #150

@rashidotm

Description

@rashidotm

when using a CachedNetworkImage , the fade in / fade out animation will not work on first load. but on second run it will work normally.

The following recording shows the unwanted behaviour (fade in / fade out not working). it happens on the first run of the app.

1.bug.on.first.start.mp4

The following recording shows the wanted behaviour. it is achieved after switching to normal Image.network widget and performing a hot reload.

2.no.bug.with.normal.widget.mp4

The following recording shows the wanted behaviour with CachedNetworkImage after switching back to its widget and performing a hot reload. mimicking a second load of the graph.

3.no.bug.with.buggy.widget.mp4

here is a minimal code to reproduce the issue

pubspec.yaml

name: graphview_image
description: "A new Flutter project."
publish_to: 'none'
version: 0.1.0

environment:
  sdk: ^3.10.1

dependencies:
  cached_network_image: ^3.4.1
  flutter:
    sdk: flutter
  graphview: ^1.5.1

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^6.0.0

flutter:
  uses-material-design: true

main.dart

import 'package:flutter/material.dart';
import 'package:graphview/GraphView.dart';
import 'package:cached_network_image/cached_network_image.dart';

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

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

  static const count = 27; // Number of nodes in the tree
  static const s = 60; // image edge size
  static const sd = s * 1.0; // Size as double
  static const levelSeparation = 100;
  static const siblingSeparation = 10;
  static const subtreeSeparation = 10;
  static const orientation = BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM;

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

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

  @override
  State<TreeViewPage> createState() => _TreeViewPageState();
}

class _TreeViewPageState extends State<TreeViewPage> {
  final Graph graph = Graph()..isTree = true;
  final GraphViewController controller = GraphViewController();
  BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration(
    levelSeparation: MyApp.levelSeparation,
    siblingSeparation: MyApp.siblingSeparation,
    subtreeSeparation: MyApp.subtreeSeparation,
    orientation: MyApp.orientation,
  );

  @override
  void initState() {
    super.initState();

    // create n nods
    final List<Node> nodes = List.generate(MyApp.count, (i) => Node.Id(i + 1));

    // create edges, parent is node at index (i)/2
    for (int i = 1; i < nodes.length; i++) {
      int parentIndex = (i - 1) ~/ 2;
      graph.addEdge(nodes[parentIndex], nodes[i]);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: GraphView.builder(
              graph: graph,
              algorithm: BuchheimWalkerAlgorithm(builder, TreeEdgeRenderer(builder)),
              controller: controller,
              animated: true,
              autoZoomToFit: false,
              builder: (Node node) {
                return NodeWidget(controller: controller, graph: graph, node: node);
              },
            ),
          ),
        ],
      ),
    );
  }
}

class NodeWidget extends StatelessWidget {
  const NodeWidget({super.key, required this.controller, required this.graph, required this.node});
  final GraphViewController controller;
  final Graph graph;
  final Node node;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        controller.toggleNodeExpanded(graph, node, animate: true);
      },
      child: Container(
        width: MyApp.sd,
        height: MyApp.sd,
        padding: const EdgeInsets.all(5),
        color: Colors.yellow,
        // toggle between BuggyWidget and NormalWidget to see the difference
        child: FadingBug(id: node.key!.value.toString()),
        // child: NormalFade(id: node.key!.value.toString()),
      ),
    );
  }
}

class FadingBug extends StatelessWidget {
  const FadingBug({super.key, required this.id});
  final String id;

  @override
  Widget build(BuildContext context) {
    return CachedNetworkImage(imageUrl: 'https://picsum.photos/seed/$id/${MyApp.s}/${MyApp.s}');
  }
}

class NormalFade extends StatelessWidget {
  const NormalFade({super.key, required this.id});
  final String id;

  @override
  Widget build(BuildContext context) {
    return Image.network('https://picsum.photos/seed/$id/${MyApp.s}/${MyApp.s}');
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions