Kevin Farel
Kevin Farel

Reputation: 157

I have laggy animation because of setState() in my code

I have animated pageview and listview that connected to each other. But I have an animation problem that caused by setState(i have tested to removed the setState and the animation works well).

import 'package:flutter/material.dart';

 const double _listheight = 80;

class LoyaltyPage extends StatefulWidget {
  @override
  _LoyaltyPageState createState() => new _LoyaltyPageState();
}

class _LoyaltyPageState extends State<LoyaltyPage> {
  PageController controller;
  ScrollController listcontroller;
  int selected = 0;
  List<String> images=[
    'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
    'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
    'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
    'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
  ];
  @override
  initState() {
    super.initState();
    controller = new PageController(
      initialPage: selected,
      keepPage: false,
      viewportFraction: 0.7,
    );
    listcontroller = new ScrollController();
  }

  @override
  dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        iconTheme: IconThemeData(color: Colors.black),
        title: Text(
          'Loyalty',
          style: TextStyle(color: Colors.black),
        ),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            flex: 3,
            child: new Container(
              child: new PageView.builder(
                  onPageChanged: (value) {
                  //ADDING THIS SET STATE CAUSE SELECTED COLOR WORKS BUT LAGGY ANIMATION
                  setState(() {
                    selected=value;
                  });
                    listcontroller.animateTo(value*_listheight,duration: Duration(milliseconds: 500),curve: Curves.ease);
                  },
                  itemCount: images.length,
                  controller: controller,
                  itemBuilder: (context, index) => builder(index)),
            ),
          ),
          Expanded(
            flex: 6,
            child: new Container(
              child: new ListView.builder(
                controller: listcontroller,
                itemCount: images.length,
                itemBuilder: (context,index) => _listbuilder(index),
              ),
            ),
          ),
        ],
      ),
    );
  }

  builder(int index) {
    return new AnimatedBuilder(
      animation: controller,
      builder: (context, child) {
        double value = 1.0;
        if (controller.position.haveDimensions) {
          value = controller.page - index;
          value = (1 - (value.abs() * .4)).clamp(0.0, 1.0);
        }
        return new Center(
          child: new SizedBox(
            height: Curves.easeOut.transform(value) * 180,
            width: Curves.easeOut.transform(value) * 270,
            child: child,
          ),
        );
      },
      child: new Card(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
          semanticContainer: true,
          clipBehavior: Clip.antiAliasWithSaveLayer,
        child:Container(
          child: Image.network(images[index],fit: BoxFit.fill,)
        ),
      ),
    );
  }

  _listbuilder(int index){
    return Container(
      height: _listheight,
      child: Column(
        children: <Widget>[
          ListTileTheme(
            selectedColor: Colors.blueAccent,
            child: ListTile(
              title: Text(images[index],maxLines: 1,overflow: TextOverflow.ellipsis,),
              subtitle: Text('Level : Gold'),
              leading: GestureDetector(
                onTap: (){
                  //ADDING THIS SET STATE CAUSE SELECTED COLOR WORKS BUT LAGGY ANIMATION
                  setState(() {
                    selected=index;
                  });
                  controller.animateToPage(index,duration: Duration(milliseconds: 500),curve: Curves.ease); 
                },
                child: Icon(
                  Icons.credit_card),
              ),
              trailing: Icon(Icons.navigate_next),
              selected: index==selected,//THIS IS THE SELECTED THAT I TRIED TO CHANGE
            ),
          ),
          Divider(height: 1,color: Colors.black45,),
        ],
      ),
    );
  }
}

I use setState at 2 places where it's on pagechanged and on leading listtile of my app.And here is my app looks like.

SNAP 1

the first one is the expected output of my app but it laggy, the second one has smooth animation but the text color doesn't change.

Upvotes: 0

Views: 4567

Answers (1)

Daniel Eberl
Daniel Eberl

Reputation: 1424

Try running your application in Release or Profile Mode.

There are performance-issues with animations in debug-mode when only a CircularProgressIndicator() is spinning. This is due to the fact that in Debug Mode, Dart gets compiled JIT instead of AOT. Thus, the Drawing Engine would need to compile 60 times / second while drawing the UI during the animation to run as smoothly as in AOT mode. This would take up a lot of resources as one might guess.

As long as you don't call setState({}) on the AnimationController..addListener() you should be fine with your specific implementation. Please refer to this article for further details on Animations and setState({}): https://medium.com/flutter-community/flutter-laggy-animations-how-not-to-setstate-f2dd9873b8fc .

Upvotes: 3

Related Questions