Daren Palmer
Daren Palmer

Reputation: 152

Animation in flutter FutureBuilder widget results in infinite loading

I'm trying to animate a container in a FutureBuilder widget which makes a request to a node js api on localhost. There seems to have no issues with the API, but I've noticed that the Container renders normally when I don't call controller.repeat(). i'm guessing that controller.repeat() doesn't work well asynchronously, but I haven't found any alternatives.

This is the code I've got so far:

class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;
  void initState() {
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 3000), vsync: this);
    animation = Tween<double>(begin: 10, end: 300).animate(controller);
    animation.addListener(() {
      setState(() {});
    });
  }

  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final url = Uri.parse("http://localhost:8080");
    return FutureBuilder(
        future: http.get(url),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            final themeList =
                Map<String, dynamic>.from(jsonDecode(snapshot.data.body));
            final keys = List.from(themeList.keys);
            controller.repeat(); // Container shows when I comment this line out
            return Center(
              child: Container(
                color: Colors.red,
                width: animation.value,
                height: animation.value,
              ),
            );
          } else {
            return Center(child: CircularProgressIndicator());
          }
        });
  }
}

Upvotes: 2

Views: 873

Answers (1)

rickimaru
rickimaru

Reputation: 2490

Please separate your animated widget. In your code, every setState(...) call will re-request the http.get(...).

Do something like this...

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const Scaffold(
        body: Center(
          child: Home(),
        ),
      ),
    );
  }
}

class Home extends StatelessWidget {
  const Home();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: Future<void>.delayed(const Duration(seconds: 2), () {}),
      builder: (context, snapshot) =>
          snapshot.connectionState == ConnectionState.done
              ? const Center(child: AnimatedContainer())
              : const Center(child: CircularProgressIndicator()),
    );
  }
}

class AnimatedContainer extends StatefulWidget {
  const AnimatedContainer();

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

class _AnimatedContainer extends State<AnimatedContainer>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 3000),
      vsync: this,
    );
    _animation = Tween<double>(begin: 10, end: 300).animate(_controller);
    _animation.addListener(() {
      setState(() {});
    });
    // _controller.repeat();
    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
      width: _animation.value,
      height: _animation.value,
    );
  }

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

Upvotes: 1

Related Questions